37

In iPhone App on click of table view cell I want to display Table view cell Accessory type Check mark for that on didSelectRowAtIndexPath i am writing code

if(indexPath.row ==0)
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType=UITableViewCellAccessoryCheckmark;
 }

and displaying check marks.

but in my case i wnt to allow user to check only on cell at a time means if user select other row then that row should checked and previously checked should be unchecked

How can I achieve that?

ios
  • 6,134
  • 20
  • 71
  • 103
  • Possible duplicate of [UITableView Checkmark ONLY ONE Row at a Time](https://stackoverflow.com/questions/10192908/uitableview-checkmark-only-one-row-at-a-time) – pkamb Oct 04 '21 at 20:12

8 Answers8

170

Keep track, in an instance variable, of which row is checked. When the user selects a new row, first uncheck the previously checked row, then check the new row and update the instance variable.

Here is more detail. First add a property to keep track of the currently checked row. It's easiest if this is an NSIndexPath.

@interface RootViewController : UITableViewController {
    ...
    NSIndexPath* checkedIndexPath;
    ...
}

...
@property (nonatomic, retain) NSIndexPath* checkedIndexPath;
...

@end

In your cellForRowAtIndexPath add the following:

if([self.checkedIndexPath isEqual:indexPath])
{
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else 
{
    cell.accessoryType = UITableViewCellAccessoryNone;
}

How you code your tableView:didSelectRowAtIndexPath: will depend on the behavior you want. If there always must be a row checked, that is, that if the user clicks on an already checked row use the following:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Uncheck the previous checked row
    if(self.checkedIndexPath)
    {
        UITableViewCell* uncheckCell = [tableView
                     cellForRowAtIndexPath:self.checkedIndexPath];
        uncheckCell.accessoryType = UITableViewCellAccessoryNone;
    }
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
    self.checkedIndexPath = indexPath;
}

If you want to allow the user to be able to uncheck the row by clicking on it again use this code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Uncheck the previous checked row
    if(self.checkedIndexPath)
    {
        UITableViewCell* uncheckCell = [tableView
                    cellForRowAtIndexPath:self.checkedIndexPath];
        uncheckCell.accessoryType = UITableViewCellAccessoryNone;
    }
    if([self.checkedIndexPath isEqual:indexPath])
    {
        self.checkedIndexPath = nil;
    }
    else
    {
        UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        self.checkedIndexPath = indexPath;
    }
}
idz
  • 12,825
  • 1
  • 29
  • 40
  • 7
    Nice. Well thought out. Thorough. Great use of code examples. Well done and thanks for the great contribution! – mbm29414 Sep 01 '11 at 12:27
  • You should add `[tableView deselectRowAtIndexPath:indexPath animated:YES];` in your `didSelectRowAtIndexPath ` – Kai Burghardt Mar 17 '15 at 10:41
  • @KaiBurghardt Nope, I shouldn't UITableView will do that for you. – idz Mar 17 '15 at 10:54
  • It is crashing if the uncheckCell is not in the visiblecells on tableView. – umakanta Sep 15 '15 at 12:27
  • @umakanta Can you post more info? Where is it crashing? Why? – idz Sep 16 '15 at 22:58
  • let You have stored the indexpath in checkedIndexPath. Now you scroll the tableview and the checkedIndexPath's cell is not visible. ( i.e. the cell became nil because of dequeuereusablecellwithidentifier ) In this scenario, in the if loop you have done UITableViewCell* uncheckCell = [tableView cellForRowAtIndexPath:self.checkedIndexPath]; so uncheckCell is nil now. So it is crashing at this time – umakanta Sep 17 '15 at 08:05
  • It is perfectly legal to use a nil object in Objective C – idz Sep 17 '15 at 19:34
5
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *newCell =[tableView cellForRowAtIndexPath:indexPath];
    int newRow = [indexPath row];
    int oldRow = [lastIndexPath row];
    if (newRow != oldRow)
    {
        newCell = [tableView  cellForRowAtIndexPath:indexPath];
        newCell.accessoryType = UITableViewCellAccessoryCheckmark;
        UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: lastIndexPath]; 
        oldCell.accessoryType = UITableViewCellAccessoryNone;
        lastIndexPath = indexPath;  
    }
}

For reference take a look at this discussion

pkamb
  • 33,281
  • 23
  • 160
  • 191
visakh7
  • 26,380
  • 8
  • 55
  • 69
3

this is a simple solution that worked for me:

in your .h file declare:

NSIndexPath *checkedCell;

then in your .m file add:

        if (checkedCell == indexPath) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
        } else { 
cell.accessoryType = UITableViewCellAccessoryNone; 
}

to the cellForRowAtIndexPath method and

checkedCell = indexPath;
[tableView reloadData]

to the didSelectRowAtIndexPath method.

Best of luck!

Johnny Rockex
  • 4,136
  • 3
  • 35
  • 55
2

I worked on your problem and got a solution

in .h file

int rowNO;
    NSIndexPath *lastIndexPth;

in . m file

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%d",indexPath.row);
    if (rowNO!=indexPath.row) {
        rowNO=indexPath.row;        
        [tableView cellForRowAtIndexPath:indexPath].accessoryType=UITableViewCellAccessoryCheckmark;
        [tableView cellForRowAtIndexPath:lastIndexPth].accessoryType=UITableViewCellAccessoryNone;
        lastIndexPth=indexPath;
    }

I hope this might help you...

Gypsa
  • 11,230
  • 6
  • 44
  • 82
2

its simple

in .h

NSIndexPath   checkedCell;

In .m

cellForRowAtIndexPath


if ([checkedCell isEqual:indexPath]) 

{
    cell.accessoryType = UITableViewCellAccessoryCheckmark;


} else
{ 
    cell.accessoryType = UITableViewCellAccessoryNone; 
}

in didSelectRowAtIndexPath

checkedCell = indexPath;

[tableView reloadData]
Didier Ghys
  • 30,396
  • 9
  • 75
  • 81
Ramsakal
  • 23
  • 4
1

I hope this one solves your problem :

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    int newRow = [indexPath row];
    int oldRow = (lastIndexPath != nil) ? [lastIndexPath row] : -1;
    
    if (newRow != oldRow)
    {
        UITableViewCell *newCell = [tableView cellForRowAtIndexPath:
                                    indexPath];
        newCell.accessoryType = UITableViewCellAccessoryCheckmark;
        
        UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: 
                                    lastIndexPath]; 
        oldCell.accessoryType = UITableViewCellAccessoryNone;
        lastIndexPath = indexPath;
    }
    
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Jayprakash Dubey
  • 35,723
  • 18
  • 170
  • 177
1

You could store NSIndexPath of the checked row as the class variable, whenever you try to the others row just access the previously checked row using the NSIndexPath variable stored as class variable and unchecked that.

Check the below post

http://www.iphonedevsdk.com/forum/iphone-sdk-development/24240-uitableviewcellaccessorycheckmark-one-checkmark-time.html

Jhaliya - Praveen Sharma
  • 31,697
  • 9
  • 72
  • 76
1

Add to your UITableViewDataSource delegate variable NSIndexPath *checkedIndex. Add to didSelectRowAtIndexPath:

checkedIndex = indexPath;
[tableView reload];

And change your cellForRowAtIndexPath: method:

cell = .. // init or dequeue
if ([indexPath isEqualTo:checkedIndex])
{
    cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
else
{
    cell.accessoryType=UITableViewCellAccessoryNone;
}
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
5hrp
  • 2,230
  • 1
  • 18
  • 18