UITableView didSelectRowAtIndexPath add additional checkmark at tap

妖精的绣舞 提交于 2019-12-03 08:17:47

The problem you are facing is caused by cell reusing.

Basically, if your UITableView has, let say 50 cells to display, it creates only 10 and then reuse them as you scroll down / scroll up. So whatever changes you did to the cell at row 0, it will be re-displayed for the row 11 as TableView uses the same cell etc.

What you want to do is to keep track of which players have been selected independently from cell. You can achieve that easily by creating a collection, let say NSMutableArray or NSMutableDictionary, which will store BOOL values in NSNumber objects, eg.

NSMutableArray *players = [NSMutableArray arrayWithCapacity:50];
for (int i = 0; i < 50; i++) {
    [players addObject:[NSNumber numberWithBool:NO]];
}

Then in didSelectRowAtIndexPath:(NSIndexPath *)indexPath you do instead of operating on cell, you will simply change the value of a corresponding NSNumber object.

Then in cellForRowAtIndexPath:(NSIndexPath *)indexPath you configure cell accessory by checking the corresponding entry in players collection.

Or if you are really, really stubborn you could replace (THIS IS NOT RECOMENDED) the following line from the cellForRowAtIndexPath:(NSIndexPath *)indexPath:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

with:

UITableViewCell *cell = nil;
Dave Kozikowski

I am using storyboards with Dynamic Prototype Cells to display a list of states I used some of the ideas above before I found this solution

Step 1

@interface StateViewController : UITableViewController
{
    NSMutableArray *checkedIndexPaths;
}

Step 2

(void)viewDidLoad
{
    [super viewDidLoad];
    self.states = [[GAIGStateStore sharedInstance]allStates];

    //Setup default array to keep track of the checkmarks
    checkedIndexPaths = [NSMutableArray arrayWithCapacity:self.states.count];
    for (int i = 0; i < self.states.count; i++) {
        [checkedIndexPaths addObject:[NSNumber numberWithBool:NO]];
    }
}

Step 3

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

    //This toggles the checkmark
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    if (cell.accessoryType == UITableViewCellAccessoryNone)
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        //This sets the array
        [checkedIndexPaths replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:YES]];

    } else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
         //This sets the array
        [checkedIndexPaths replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:NO]];

    }


}

Step 4

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:stateCell forIndexPath:indexPath];

    UILabel *stateLabel = (UILabel *)[cell viewWithTag:1000];

    StateProvince *myState = [self.states objectAtIndex:indexPath.row];

    stateLabel.text = myState.label;

    //Now set the check marks
    // Assume cell not checked;
    [cell setAccessoryType:UITableViewCellAccessoryNone];

    NSNumber *num = [checkedIndexPaths objectAtIndex:indexPath.row];


    if (num == [NSNumber numberWithBool:YES]) {
           [cell setAccessoryType:UITableViewCellAccessoryCheckmark];
    }


    return cell;
}

For others coming here (like I did) to see why their table selects random cells, you have to add something like the following to your cellForRowAtIndexPath:

// Assume cell not checked;
[cell setAccessoryType:UITableViewCellAccessoryNone];
for (int i = 0; i < checkedIndexPaths.count; i++) {
    NSUInteger num = [[checkedIndexPaths objectAtIndex:i] row];

    if (num == indexPath.row) {
        [cell setAccessoryType:UITableViewCellAccessoryCheckmark];
    }
}

I keep a NSMutableArray called checkedIndexPaths so that I know which indexPaths are checked. Keeping such an array allows you to easily limit the number of cells a user can check. Here's an example of my didSelectRowAtIndexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    // uncheck if already checked
    if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [checkedIndexPaths removeObject:indexPath];
    }
    else {
        // make sure no more than 3 are selected
        if ([checkedIndexPaths count] < 3) {

            // check row
            cell.accessoryType = UITableViewCellAccessoryCheckmark;
            // add it to our list of checked indexes
            [checkedIndexPaths addObject:indexPath];
        } else {
            UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Note" 
                                                            message:@"You can only select 3 rows." 
                                                           delegate:nil 
                                                  cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
        }
    }  
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!