Repository navigation
Conversation
| */ | ||
| class PagerScrollDelegate: NSObject, UIScrollViewDelegate, UICollectionViewDelegate { | ||
| weak var originalDelegate: UICollectionViewDelegate? | ||
| weak var originalDelegate: UIScrollViewDelegate? |
There was a problem hiding this comment.
q: Could you explain this change?
There was a problem hiding this comment.
On iOS 15 the delegate of the embedded scroll view is UIKit's private _UICollectionViewOrthogonalScrollerSectionController. It only conforms to UIScrollViewDelegate, not UICollectionViewDelegate, and PagerScrollDelegate now forwards to it too.
|
|
||
| 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) |
There was a problem hiding this comment.
q: Why is this casting needed? Why can't we have weak var originalDelegate: UICollectionViewDelegate?
There was a problem hiding this comment.
Because of the type change on line 7. With UICollectionViewDelegate? we'd have to store scrollView.delegate as? UICollectionViewDelegate, which is nil for it, so its scroll callbacks would stop being forwarded.
The cast always succeeds here. These two methods are only called on the collection view's instance, and the original delegate there is SwiftUI's coordinator, which conforms to UICollectionViewDelegate. I checked this in lldb on iOS 15.5 and 26.5.
Summary
Fixes #1080.
On iOS 15,
onPageScrollandonPageScrollStateChangedare never emitted, so the tab indicator of react-native-tab-view / material-top-tabs doesn't follow the page.onPageSelectedstill works.Same root cause as #1148: on iOS 15 the paging is done by a scroll view SwiftUI embeds in the collection view (
_UICollectionViewOrthogonalScrollerEmbeddedScrollView), andPagerScrollDelegateis only set on the collection view, so it never sees the scroll.This puts a
PagerScrollDelegatein front of the embedded scroll view's delegate as well, forwarding to the original one. The embedded scroll view doesn't exist yet when introspect runs, so it's attached fromcollectionView(_:willDisplay:forItemAt:). It's a no-op on iOS 16+, like the rest ofPagerViewIOS15Compat.Before:
ios15-material-top-tabs-before.mp4
After:
ios15-material-top-tabs-after.mp4
Test Plan
Example app on an iOS 15.5 simulator (iPad Air 2):
State: dragging,scrollandState: idle. Still works after "Add new page".The e2e suite passes on iOS 26.5.
We also applied this as a patch to 8.0.5 in our app, and the tabs of both react-native-tab-view and react-native-collapsible-tab-view work again on iOS 15.5.
Compatibility
Checklist
README.md