ok, in my whole career as iOS developer, this might be the first case where subclassing UITableView IS the best answer!
UITableView uses a pan gesture recognizer to detect the scrolling gesture. The tableview itself must be it's delegate, therefore we can stop the gesture from being detected by subclassing UITableView:
import UIKit
class DontScrollTableView: UITableView, UIGestureRecognizerDelegate {
var dontScroll = false
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return !dontScroll
}
}
in our UITableViewDelegate implementation we can toggle scrolling:
var previouslySelectedIndexPath: IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let tv = tableView as? DontScrollTableView {
if let lastSelected = previouslySelectedIndexPath {
tv.dontScroll = lastSelected != indexPath
if lastSelected == indexPath {
tableView.deselectRow(at: indexPath, animated: false)
previouslySelectedIndexPath = nil
} else {
previouslySelectedIndexPath = indexPath
}
} else {
tv.dontScroll = true
previouslySelectedIndexPath = indexPath
}
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let tv = tableView as? DontScrollTableView {
tv.dontScroll = false
}
}