Reputation:
How do I observe cell accessory Type UITableViewCellAccessoryCheckmark
is checked or not?
In my app I added UITableView
in a UIAlertView
. I also used
cell.accessoryType = UITableViewCellAccessoryCheckmark;
In my tableView, i have 9 rows. When the user taps on first row then all rows become checked except second row. The user can check any row/rows as he wishes. When the user taps on the second row then only the second row is checked.
Thanks in Advance :)
Upvotes: 1
Views: 1318
Reputation: 18363
I know this has already been answered, but I've had a lot of luck maintaining a NSMutableIndexSet instance, and adding / removing indexes for checked / unchecked rows.
The key methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSInteger index = indexPath.row;
cell.accessoryType = ([self.selectedRowsIndexSet containsIndex:index]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
cell.textLabel.text = [NSString stringWithFormat:@"Row %d",index];
return cell;
}
This is fairly straight-foward - check to see if the index is selected and set the accessory accordingly.
For a multi-select (i.e. any call can be selected) implementation of tableView:didSelectRowAtIndexPath:
looks like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index = indexPath.row;
if ([self.selectedRowsIndexSet containsIndex:index])
[self.selectedRowsIndexSet removeIndex:index];
else
[self.selectedRowsIndexSet addIndex:index];
[tableView reloadRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];
}
Just add the index, reload the table. For a single select it's pretty quick too
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger oldIndex = [self.selectedRowsIndexSet firstIndex];
NSInteger newIndex = indexPath.row;
[self.selectedRowsIndexSet removeIndex:oldIndex];
[self.selectedRowsIndexSet addIndex:newIndex];
[tableView reloadRowsAtIndexPaths:@[ indexPath, [NSIndexPath indexPathForRow:oldIndex inSection:0] ]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
Can of course get more complicated with more sections, whether selections in some sections depend on selections in others, and so on. I've been using per-section arrays of index sets for the former and then various complex logic involving the underlying data model for the latter. But keeping the basic table view interaction at the level of just querying an index set helps keep these methods pretty short and readable.
Upvotes: 0
Reputation: 1877
if ([[tableView cellForRowAtIndexPath:indexPath ] accessoryType] == UITableViewCellAccessoryCheckmark){
}
else{
}
Upvotes: 0
Reputation: 80271
While the answer of @dasblinkenlight is certainly more elegant, it might be too advanced for you.
The essence is to keep track of which cells are checked and which are unchecked. Whenever something changes, reload the table view to updated the checkmarks.
You need to create your own variable to track this. A bitmap is very economical and elegant, but it might be difficult to understand and not scalable to a large number of rows. Alternatively, you could use an array.
NSMutableArray *checkedArray = [NSMutableArray arrayWithObjects:
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
nil];
To change a row given the index path:
[checkedArray replaceObjectAtIndex:indexPath.row
withObject:[NSNumber numberWithBool:YES]]; //add
[checkedArray replaceObjectAtIndex:indexPath.row
withObject:[NSNumber numberWithBool:NO]]; //remove
And in cellForRowAtIndexPath
make sure you set the accessory explicitly:
if ([[checkedArray objectAtIndex:indexPath.row] boolValue]) {
cell.accessoryType = UITableViewCellAccessoryTypeCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryTypeNone;
}
Upvotes: 1
Reputation: 726929
Since the number of items is so small, you can model the checked/unchecked state with a single integer and bitmasks. Use the lower nine bits of the number to indicate a checked/unchecked state:
// Add an instance variable to your view controller
// Initialize to 0 in the designated initializer
NSUInteger checkedFlags;
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *res = ... // Dequeue the cell and so on
res.accessoryType = (checkedFlags & (1 << indexPath.row))
? UITableViewCellAccessoryCheckmark
: UITableViewCellAccessoryNone;
... // The rest of the method
}
Here is how you check/uncheck/toggle an individual row: in the tableView:willSelectRowAtIndexPath:
of your delegate, do one of these:
checkedFlags |= (1 << indexPath.row); // Check
checkedFlags &= ~(1 << indexPath.row); // Uncheck
checkedFlags ^= (1 << indexPath.row); // Toggle
If you want to check/uncheck multiple rows at once, mask with a number composed of the bits corresponding to rows being checked/unchecked in the binary form For example, the number that has bits 2..8 set is 0x01FC0
.
checkedFlags |= 0x1FC0; // Check rows #3 through #9
Don't forget to call reloadData
after manipulating the checkedFlags
variable.
Upvotes: 1