Created
June 21, 2023 17:36
-
-
Save VaslD/c266ad523c9d1c78c9e439a97819ae4c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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