52

Am I correct in thinking that to change the checkmark for "on" to "off", I must change the CellAccessoryType between none and checkmark on the didSelectRowAtIndexPath?

Because I have done this but I have noticed the behaviour is not perfectly identical to like the checkmark cells on the auto lock settings on the iphone.

Or is there some other way checkmarks are meant to be handled?

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Jonathan.
  • 53,997
  • 54
  • 186
  • 290

8 Answers8

82
  1. Keep a property in your view controller called selectedRow, which represents the index of a row that represents the checked item in a table section.

  2. In your view controller's -tableView:cellForRowAtIndexPath: delegate method, set the accessoryType of the cell to UITableViewCellAccessoryCheckmark if the cell's indexPath.row equals the selectedRow value. Otherwise, set it to UITableViewCellAccessoryNone.

  3. In your view controller's -tableView:didSelectRowAtIndexPath: delegate method, set the selectedRow value to the indexPath.row that is selected, e.g.: self.selectedRow = indexPath.row

Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
  • Sorry, I did not mean that I had multiple checkmark cells (more like radio buttons). Just they didn't animate as smoothly (but I fixed that now). But your answer means I am using the correct methods :) – Jonathan. May 09 '10 at 12:27
  • 8
    To add to Alex's solution - to make the check mark appear when you tap the cell, you must also put in [tableview reloadData] after you set the selected cell. – Owen Pierce Jan 17 '12 at 03:14
  • 6
    That's easy, but there might be a performance hit from reloading data into the whole table. Because you know what `indexPath.row` you need to update, you only need to update that row, which can be done with the table view method `-reloadRowsAtIndexPaths:withRowAnimation:` For more details: http://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006943-CH3-SW40 – Alex Reynolds Jan 18 '12 at 17:13
  • @AlexReynolds can you please elaborate when you said set the accessoryType of the cell to UITableViewCellAccessoryCheckmark if the cell's indexPath.row equals the selectedRow value. Otherwise, set it to UITableViewCellAccessoryNone. – codejunkie Mar 20 '12 at 18:15
  • Either the row needs a checkmark, or it doesn't. If it is the selected row (by comparing the index path row and selected row values) then mark it. Otherwise, don't. – Alex Reynolds Mar 20 '12 at 20:01
  • I did this, but the checked box stays highlighted in gray instead of fading out like it does in apple apps. – whoKnows Nov 09 '15 at 22:39
61

Another solution:

-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSIndexPath *oldIndex = [self.tableView indexPathForSelectedRow];
    [self.tableView cellForRowAtIndexPath:oldIndex].accessoryType = UITableViewCellAccessoryNone;
    [self.tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
    return indexPath;
}

And yeah: you don't have to check if oldIndex is nil :)


Swift 3 and later:

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    if let oldIndex = tableView.indexPathForSelectedRow {
        tableView.cellForRow(at: oldIndex)?.accessoryType = .none
    }
    tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark

    return indexPath
}
Constantino Tsarouhas
  • 6,846
  • 6
  • 43
  • 54
Yvo
  • 18,681
  • 11
  • 71
  • 90
5

swift:

var selectedCell:UITableViewCell?{
    willSet{
        selectedCell?.accessoryType = .None
        newValue?.accessoryType = .Checkmark
    }
}

then:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    selectedCell = self.tableView.cellForRowAtIndexPath(indexPath)
    self.mapView.selectAnnotation(self.mapView.annotations[indexPath.row], animated: true)
}
Ben
  • 3,832
  • 1
  • 29
  • 30
5

For swift

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
  }

  func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .none
  }
BatyrCan
  • 6,773
  • 2
  • 14
  • 23
4

Zyphrax suggested a great solution that worked great for me! And if you need to clear the previous selected row, just use:

[self.tableView reloadData]; 

in

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
neowinston
  • 7,584
  • 10
  • 52
  • 83
3

It should be

didHighlightRowAtIndexPath

instead of

tableView:didSelectRowAtIndexPath

Abdul Rahman
  • 2,097
  • 4
  • 28
  • 36
Abid Malik
  • 157
  • 8
3

Alex answer worked for me only after adding reload table , in .h

{
  int selectedCell;
}
@property(nonatomic,readwrite)int selectedCell;

in .m *cellForRowAtIndexPath*

if(indexPath.row == selectedCell)
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        cell.selected = YES;
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
        cell.selected = NO;
    }

and in anywhere didHighlightRowAtIndexPath or didSelectRowAtIndexPath

 self.selectedCell = indexPath.row;
    [self.tableView reloadData]; 
iMeMyself
  • 1,649
  • 13
  • 28
0

If you want to use your custom image as accessoryType use below code

-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UIImageView *imgCheckMark = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"select_icon.png"]];
    [imgCheckMark setFrame:CGRectMake(self.view.frame.size.width - 30, 25, 14, 18)];
    imgCheckMark.tag = 1000+indexPath.row;

    NSIndexPath *oldIndex = [self.tblSelectService indexPathForSelectedRow];
    [self.tblSelectService cellForRowAtIndexPath:oldIndex].accessoryView = UITableViewCellAccessoryNone;
    [self.tblSelectService cellForRowAtIndexPath:indexPath].accessoryView = imgCheckMark;
    return indexPath;
}
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81