Skip to content

Instantly share code, notes, and snippets.

@VaslD
Created June 21, 2023 17:36
Show Gist options
  • Save VaslD/c266ad523c9d1c78c9e439a97819ae4c to your computer and use it in GitHub Desktop.
Save VaslD/c266ad523c9d1c78c9e439a97819ae4c to your computer and use it in GitHub Desktop.
import UIKit
open class UITableViewPlus: UITableView, UITableViewDelegate {
// MARK: Scroll
override public init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
super.delegate = self
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
super.delegate = self
}
private var _delegate: UITableViewDelegate?
override open var delegate: UITableViewDelegate? {
get { self._delegate }
set {
self._delegate = newValue
super.delegate = self
}
}
override open func responds(to selector: Selector!) -> Bool {
self.responds(to: selector) || self._delegate?.responds(to: selector) == true
}
override open func forwardingTarget(for selector: Selector!) -> Any? {
self._delegate?.responds(to: selector) == true ? self._delegate : nil
}
private var scrollToItemCompletionHandler: ((UITableView, Bool) -> Void)?
open func scrollToRow(at indexPath: IndexPath, at scrollPosition: UITableView.ScrollPosition, animated: Bool,
completion: @escaping (UITableView, _ animated: Bool) -> Void) {
// Fast path: Non-visible items must be scrolled to.
if self.indexPathsForVisibleRows?.contains(indexPath) != true {
self.scrollToItemCompletionHandler = completion
self.scrollToRow(at: indexPath, at: scrollPosition, animated: true)
return
}
// Slow path: visible items may be scrolled to if not already in position.
let currentOffset = self.contentOffset.y
self.scrollToRow(at: indexPath, at: scrollPosition, animated: false)
let targetOffset = self.contentOffset.y
// Check if already in position.
if (currentOffset * 100).rounded() == (targetOffset * 100).rounded() {
completion(self, false)
return
}
// Scroll will happen. Revert content offset and start animation.
self.contentOffset.y = currentOffset
self.scrollToItemCompletionHandler = completion
self.scrollToRow(at: indexPath, at: scrollPosition, animated: true)
}
public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
self.scrollToItemCompletionHandler?(self, true)
self.scrollToItemCompletionHandler = nil
self._delegate?.scrollViewDidEndScrollingAnimation?(scrollView)
}
// MARK: Reload
open func reloadRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation,
completion: @escaping (UITableView, _ animated: Bool) -> Void) {
self.performBatchUpdates {
self.reloadRows(at: indexPaths, with: animation)
} completion: {
completion(self, $0)
}
}
open func reloadSections(_ sections: IndexSet, with animation: UITableView.RowAnimation,
completion: @escaping (UITableView, _ animated: Bool) -> Void) {
self.performBatchUpdates {
self.reloadSections(sections, with: animation)
} completion: {
completion(self, $0)
}
}
private var reloadCompletionHandler: ((UITableView) -> Void)?
open func reloadData(completion: @escaping (UITableView) -> Void) {
self.reloadCompletionHandler = completion
self.reloadData()
}
override open func layoutSubviews() {
super.layoutSubviews()
self.reloadCompletionHandler?(self)
self.reloadCompletionHandler = nil
}
// MARK: Auto Layout
override open var contentSize: CGSize {
didSet { self.invalidateIntrinsicContentSize() }
}
override open var intrinsicContentSize: CGSize {
CGSize(width: UIView.noIntrinsicMetric, height: self.contentSize.height)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment