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() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
layoutSubviews
is invoked by the collection view when the component is "rendered" (not necessarily on-screen)UIScrollView
containers and observe thecontentOffset
property on themcontentOffset
prop changes, we check if our "mostly visible" status (>50%) has changed and if so, we log itprepareForReuse
is 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