Created
July 7, 2025 18:59
-
-
Save justindarc/84c5821bac80579aa56c45ecc10a95f4 to your computer and use it in GitHub Desktop.
ObservableCollectionViewCell
This file contains hidden or 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
| // | |
| // ObservableCollectionViewCell.swift | |
| // | |
| // Created by Justin D'Arcangelo on 7/3/25. | |
| // | |
| import UIKit | |
| class ObservableCollectionViewCell: UICollectionViewCell { | |
| var isMostlyVisible: Bool { | |
| guard !isHidden, alpha > 0, !bounds.isEmpty, let window, window.hitTest(window.convert(center, from: superview), with: nil) == self else { | |
| return false | |
| } | |
| return true | |
| } | |
| private var scrollViews: [UIScrollView] { | |
| let superviews = Array(sequence(first: superview, next: { $0?.superview })) | |
| return superviews.filter({ $0 is UIScrollView }) as? [UIScrollView] ?? [] | |
| } | |
| @IBOutlet var label: UILabel! | |
| override func prepareForReuse() { | |
| for observedScrollView in observedScrollViews { | |
| observedScrollView.removeObserver(self, forKeyPath: "contentOffset") | |
| } | |
| observedScrollViews.removeAll() | |
| super.prepareForReuse() | |
| } | |
| override func layoutSubviews() { | |
| for scrollView in scrollViews { | |
| if !observedScrollViews.contains(scrollView) { | |
| scrollView.addObserver(self, forKeyPath: "contentOffset", context: nil) | |
| observedScrollViews.insert(scrollView) | |
| } | |
| } | |
| checkVisibility() | |
| super.layoutSubviews() | |
| } | |
| private var observedScrollViews: Set<UIScrollView> = [] | |
| private var wasPreviouslyMostlyVisible: Bool = false | |
| private func checkVisibility() { | |
| if wasPreviouslyMostlyVisible != isMostlyVisible { | |
| print("isMostlyVisible", label.text!, isMostlyVisible) | |
| wasPreviouslyMostlyVisible = isMostlyVisible | |
| } | |
| } | |
| override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { | |
| checkVisibility() | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
layoutSubviewsis invoked by the collection view when the component is "rendered" (not necessarily on-screen)UIScrollViewcontainers and observe thecontentOffsetproperty on themcontentOffsetprop changes, we check if our "mostly visible" status (>50%) has changed and if so, we log itprepareForReuseis invoked by the collection view when the component is about to be recycled/un-rendered and at that point we stop observing the parent scroll views