UITableView tap to deselect cell
Here is an even cleaner solution:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[tableView indexPathForSelectedRow] isEqual:indexPath]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
return nil;
}
return indexPath;
}
You can actually do this using the delegate method willSelectRowAtIndexPath:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isSelected]) {
// Deselect manually.
[tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath];
return nil;
}
return indexPath;
}
Note that deselectRowAtIndexPath:
won't call the delegate methods automatically, so you need to make those calls manually.
When using "Multiple Selection" mode, "didSelectRowAtIndexPath" will not be called when you click a row that is already selected. More than one row can still be selected programatically in "Single Selection" mode and the rows will trigger didSelectRowAtIndexPath on all clicks.
Just a heads up to anyone who was having the same problems.
in Swift 4:
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if let indexPathForSelectedRow = tableView.indexPathForSelectedRow,
indexPathForSelectedRow == indexPath {
tableView.deselectRow(at: indexPath, animated: false)
return nil
}
return indexPath
}