How to prevent UITableView rows from being deselected during a swipe action?

Howdy!

Is it possible to prevent UITableView rows from being deselected during a swipe action? I found this old forum thread, but I am not sure I understand either solution. Are there hooks to detect when a swipe action begins?

Thanks, smkuehnhold

You could try to:

  • save the lastSelectedCell in a property of the VC
  • update it when you select a cell
  • at the end of swipe, select again this cell

@Claude31 The problem with this approach is that the cell remains deselected while performing the swipe action, which I do not want. Unless I am misunderstanding what you mean by at the end of the swipe. Where would you place this functionality? tableView(_:didEndEditingRowAt:)?

I would put in the handlers of UIContextualAction of the swipe.

Some typical code:

override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    
    let cell = tableView.cellForRow(at: indexPath) as! MarqueTableViewCell
    let recordAction = UIContextualAction(style: .normal, title: nil, handler: {
        (action, sourceview, completionhandler) in
        
        // Reselect here
        completionhandler(true)
    })
    
    let swipe = UISwipeActionsConfiguration(actions: [recordAction])
    return swipe
    
}

I see. However, I think that has the same problem. Sometime after tableView(_:didBeginEditingRowAt:) is called, the selected rows of the table view are unset. With your method, the selected rows are only reset when the action is performed. So there is a gap of indefinite length where the previously selected cells remain unselected. Also, what happens when a user chooses to not perform the action?

the selected rows are only reset when the action is performed.

Not only, you can do it wherever necessary, for instance in didSelectRow

I've not tried it, but you could also reselect just before return swipe.

you could also reselect just before return swipe.

This does not work, because tableView(_:leadingSwipeActionsConfigurationForRowAt:) and tableView(_:trailingSwipeActionsConfigurationForRowAt:) are called before the selected rows are unset.

in didSelectRow

I'm assuming you mean willDeselectRow/didDeselectRow? Unfortunately, it does not work becuase it does not seem the deselection caused by the swipe action calls these methods :(

But my main question is when do you re-apply the selection. Because doing it in tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) or didDeselectRow does not work for the above reasons.

I found the following example in the docs that maybe indicates that I was misusing the built-in functionality regarding cell selection (see Managing Selection Lists)?

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // Unselect the row.
    tableView.deselectRow(at: indexPath, animated: false)
    
    // Did the user tap on a selected filter item? If so, do nothing.
    let selectedFilterRow = selectedFilters[indexPath.section]
    if selectedFilterRow == indexPath.row {
        return
    }

    // **
    // NOTE:  Why else would you "deselect" in didSelectRowAt?
    // **
    // Remove the checkmark from the previously selected filter item.
    if let previousCell = tableView.cellForRow(at: IndexPath(row: selectedFilterRow, section: indexPath.section)) {
        previousCell.accessoryType = .none
    }
    
    // Mark the newly selected filter item with a checkmark.
    if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .checkmark
    }
    
    // Remember this selected filter item.
    selectedFilters[indexPath.section] = indexPath.row
}

If that is the case, then really the only solution to my underlying question "how do I prevent UIKit from implicitly de-selecting my cells" I think is to mantain your own storage of "selected items" seperate from what is included in the table view (like what the example did with selectedFilters). At least this is what I ended up doing.

This doesn't really answer the original question, but I think my reason for asking this question was misguided.

How to prevent UITableView rows from being deselected during a swipe action?
 
 
Q