This is a follow-up to How to get notified when a tableViewController finishes animating the push onto a nav stack.
In a tableView I want to deselect a
Implementing this in a Swift extension.
//strong ref required
private var lastDelegate : UITableViewScrollCompletionDelegate! = nil
private class UITableViewScrollCompletionDelegate : NSObject, UITableViewDelegate {
let completion: () -> ()
let oldDelegate : UITableViewDelegate?
let targetOffset: CGPoint
@objc private func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
scrollView.delegate = oldDelegate
completion()
lastDelegate = nil
}
init(completion: () -> (), oldDelegate: UITableViewDelegate?, targetOffset: CGPoint) {
self.completion = completion
self.oldDelegate = oldDelegate
self.targetOffset = targetOffset
super.init()
lastDelegate = self
}
}
extension UITableView {
func scrollToRowAtIndexPath(indexPath: NSIndexPath, atScrollPosition scrollPosition: UITableViewScrollPosition, animated: Bool, completion: () -> ()) {
assert(lastDelegate == nil, "You're already scrolling. Wait for the last completion before doing another one.")
let originalOffset = self.contentOffset
self.scrollToRowAtIndexPath(indexPath, atScrollPosition: scrollPosition, animated: false)
if originalOffset.y == self.contentOffset.y { //already at the right position
completion()
return
}
else {
let targetOffset = self.contentOffset
self.setContentOffset(originalOffset, animated: false)
self.delegate = UITableViewScrollCompletionDelegate(completion: completion, oldDelegate: self.delegate, targetOffset:targetOffset)
self.scrollToRowAtIndexPath(indexPath, atScrollPosition: scrollPosition, animated: true)
}
}
}
This works for most cases although the TableView delegate is changed during the scroll, which may be undesired in some cases.