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\
Swift 5.
In the UITableViewDelegate
, it's as simple as follows:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
I was after the same thing but @occulus' answer provided me the hint I was missing.
It made me realize the way to get this done is to allow multiple selection in the table view and manually deselect previously selected rows when a new row is selected using one of the delegate methods.
It seems quite natural that in single selection mode, the table view tries to leave one row selected as much as possible, thus not deselecting on tapping a selected row.
Maybe my question wasn't specific enough, but the two answers are a bit wide of what I was after.
It seems this isn't possible, and I went with a gesture recognizer of the cell to manually set selected / unselected state.
From @prisonerjohn, in case someone wonders how to check if the delegate responds to the selector as @Patrick said, in Swift 3:
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
guard let cell = tableView.cellForRow(at: indexPath) else {
// Handle invalid cell
...
}
if cell.isSelected {
if let respond = tableView.delegate?.responds(
to: #selector(tableView(_:willDeselectRowAt:))),
respond == true {
tableView.delegate?.tableView!(tableView, willDeselectRowAt: indexPath)
}
tableView.deselectRow(at: indexPath, animated: true)
if let respond = tableView.delegate?.responds(
to: #selector(tableView(_:didDeselectRowAt:))),
respond == true {
tableView.delegate?.tableView!(tableView, didDeselectRowAt: indexPath)
}
return nil
}
return indexPath
}
Swift version of prisonerjohn's answer :
public func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
let cell = tableView.cellForRowAtIndexPath(indexPath)
if (cell?.selected ?? false) {
// Deselect manually.
tableView.delegate!.tableView?(tableView, willDeselectRowAtIndexPath: indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
tableView.delegate!.tableView?(tableView, didDeselectRowAtIndexPath: indexPath)
return nil
}
return indexPath;
}
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.