Skip to content

Instantly share code, notes, and snippets.

@VaslD
Created June 21, 2023 17:37
Show Gist options
  • Save VaslD/e616d00609392a8d5c9da1513034046f to your computer and use it in GitHub Desktop.
Save VaslD/e616d00609392a8d5c9da1513034046f to your computer and use it in GitHub Desktop.
import UIKit
open class UICollectionViewPlus: UICollectionView, UICollectionViewDelegate {
// MARK: Scroll
override public init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
super.delegate = self
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
super.delegate = self
}
private var _delegate: UICollectionViewDelegate?
override open var delegate: UICollectionViewDelegate? {
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: ((UICollectionView, Bool) -> Void)?
open func scrollToItem(at indexPath: IndexPath, at scrollPosition: UICollectionView.ScrollPosition, animated: Bool,
completion: @escaping (UICollectionView, _ animated: Bool) -> Void) {
// Fast path: Non-visible items must be scrolled to.
if !self.indexPathsForVisibleItems.contains(indexPath) {
self.scrollToItemCompletionHandler = completion
self.scrollToItem(at: indexPath, at: scrollPosition, animated: true)
return
}
// Slow path: visible items may be scrolled to if not already in position.
let currentOffset = self.contentOffset
self.scrollToItem(at: indexPath, at: scrollPosition, animated: false)
let targetOffset = self.contentOffset
// Check if already in position.
if (currentOffset.x * 100).rounded() == (targetOffset.x * 100).rounded(),
(currentOffset.y * 100).rounded() == (targetOffset.y * 100).rounded() {
completion(self, false)
return
}
// Scroll will happen. Revert content offset and start animation.
self.contentOffset = currentOffset
self.scrollToItemCompletionHandler = completion
self.scrollToItem(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 reloadItems(at indexPaths: [IndexPath],
completion: @escaping (UICollectionView, _ animated: Bool) -> Void) {
self.performBatchUpdates {
self.reloadItems(at: indexPaths)
} completion: {
completion(self, $0)
}
}
open func reloadSections(_ sections: IndexSet,
completion: @escaping (UICollectionView, _ animated: Bool) -> Void) {
self.performBatchUpdates {
self.reloadSections(sections)
} completion: {
completion(self, $0)
}
}
private var reloadCompletionHandler: ((UICollectionView) -> Void)?
open func reloadData(completionHandler: @escaping (UICollectionView) -> Void) {
self.reloadCompletionHandler = completionHandler
self.reloadData()
}
override open func layoutSubviews() {
super.layoutSubviews()
self.reloadCompletionHandler?(self)
self.reloadCompletionHandler = nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment