Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions ios/PagerScrollDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import UIKit
Scroll delegate used to control underlying TabView's collection view.
*/
class PagerScrollDelegate: NSObject, UIScrollViewDelegate, UICollectionViewDelegate {
weak var originalDelegate: UICollectionViewDelegate?
weak var originalDelegate: UIScrollViewDelegate?
Comment thread
troZee marked this conversation as resolved.
weak var delegate: PagerViewProviderDelegate?
var orientation: UICollectionView.ScrollDirection = .horizontal

Expand Down Expand Up @@ -78,11 +78,13 @@ class PagerScrollDelegate: NSObject, UIScrollViewDelegate, UICollectionViewDeleg
}

func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
originalDelegate?.collectionView?(collectionView, didEndDisplaying: cell, forItemAt: indexPath)
(originalDelegate as? UICollectionViewDelegate)?.collectionView?(collectionView, didEndDisplaying: cell, forItemAt: indexPath)
Comment thread
troZee marked this conversation as resolved.
}

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
originalDelegate?.collectionView?(collectionView, willDisplay: cell, forItemAt: indexPath)
// iOS 15 only, see PagerViewIOS15Compat.swift (delete together with the iOS 15 support).
PagerViewIOS15Compat.attachScrollDelegate(to: collectionView, delegate: delegate)
(originalDelegate as? UICollectionViewDelegate)?.collectionView?(collectionView, willDisplay: cell, forItemAt: indexPath)
}

override func responds(to aSelector: Selector!) -> Bool {
Expand Down
25 changes: 23 additions & 2 deletions ios/PagerViewIOS15Compat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ import UIKit
/// collection view (private class `_UICollectionViewOrthogonalScrollerEmbeddedScrollView`), while
/// the collection view itself only scrolls vertically. Because `PagerView` can only toggle the
/// collection view, on iOS 15 `scrollEnabled={false}` / `overdrag={false}` never reached the view
/// that actually handles the swipe.
/// that actually handles the swipe. For the same reason `PagerScrollDelegate`, installed on the
/// collection view, never saw the paging scroll, so `onPageScroll` / `onPageScrollStateChanged`
/// were never emitted.
///
/// On iOS 16 and later the collection view itself is the pager, so none of this is needed — the
/// `#available` checks below make every function in here a no-op on those versions.
///
/// - Note: Delete this file together with the two `PagerViewIOS15Compat` calls in `PagerView.swift`
/// once the minimum supported iOS version is 16.
/// and the one in `PagerScrollDelegate.swift` once the minimum supported iOS version is 16.
enum PagerViewIOS15Compat {
private static var scrollDelegateKey: UInt8 = 0

/// Mirrors `scrollEnabled` onto the scroll views SwiftUI embedded in the paging collection view.
static func applyScrollEnabled(_ scrollEnabled: Bool, to collectionView: UICollectionView?) {
if #available(iOS 16, *) {
Expand All @@ -33,6 +37,23 @@ enum PagerViewIOS15Compat {
pagingScrollViews(in: collectionView).forEach { $0.bounces = overdrag }
}

/// Puts a `PagerScrollDelegate` in front of the delegate of the scroll views SwiftUI embedded in
/// the paging collection view. They only exist once the collection view has laid out its pages.
static func attachScrollDelegate(to collectionView: UICollectionView, delegate: PagerViewProviderDelegate?) {
if #available(iOS 16, *) {
return
}

for scrollView in pagingScrollViews(in: collectionView) where !(scrollView.delegate is PagerScrollDelegate) {
let scrollDelegate = PagerScrollDelegate()
scrollDelegate.originalDelegate = scrollView.delegate
scrollDelegate.delegate = delegate
// `UIScrollView.delegate` is weak; the scroll view owns its delegate instead.
objc_setAssociatedObject(scrollView, &scrollDelegateKey, scrollDelegate, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
scrollView.delegate = scrollDelegate
}
}

/// Scroll views that SwiftUI embedded in the paging collection view.
///
/// Scroll views that belong to the pages' React Native content live inside the paging cells, so
Expand Down
Loading