I have a UITableViewCell
that is selected when tapped. During this selected state, if the user taps the cell again, I want the cell to deselect.
I can\
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
}
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.
Leave the single selection mode on, but override the following funcs like this:
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if tableView.indexPathsForSelectedRows?.contains(indexPath) ?? false {
tableView.deselectRow(at: indexPath, animated: true)
return nil
}
return indexPath
}
override func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
return nil
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isSelected]) {
// Deselect manually.
if ([tableView.delegate respondsToSelector:@selector(tableView:willDeselectRowAtIndexPath:)]) {
[tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([tableView.delegate respondsToSelector:@selector(tableView:didDeselectRowAtIndexPath:)]) {
[tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath];
}
return nil;
}
return indexPath;
}
When you select a cell this delegate method is triggered.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *theUITableViewCell = [tableView cellForRowAtIndexPath:path];
if (theUITableViewCell.selected == YES){
self.tableView deselectRowAtIndexPath:<#(NSIndexPath *)#> animated:<#(BOOL)#>
// Do more thing
}else{
// By default, it is highlighted for selected state
}
}
It's pseudo code.
You can try this one, it's works for me (for single selection or multiple selections):
A. allocate a private NSMutableArray in viewDidLoad like:
@interface XXXViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
NSMutableArray * selectedZoneCellIndexPaths;
}
- (void)viewDidLoad
{
selectedZoneCellIndexPaths = [[NSMutableArray alloc] init];
}
B. in UITableViewDelegate didSelectRow add following lines
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
for (NSIndexPath * iter in selectedZoneCellIndexPaths)
{
if (indexPath.section == iter.section && indexPath.row == iter.row)
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[selectedZoneCellIndexPaths removeObject:iter];
return;
}
}
[selectedZoneCellIndexPaths addObject:indexPath];
return;
}