Repository navigation
Conversation
|
Thank you for your contribution. Is it possible to create a separate file with all of those changes and wrap it with macro like this? iOS 15 is very old, and we want to remove it in the future |
There was a problem hiding this comment.
🟢 Approval recommended
The focused implementation addresses the iOS 15 hierarchy without affecting scroll views inside page content.
0 open findings
What changed in this PR
Fixes iOS 15 paging so scrollEnabled and overdrag also apply to SwiftUI’s embedded paging scroll view.
Changes:
- Discovers paging scroll views while excluding page-content cells.
- Centralizes scroll and bounce state updates across all lifecycle paths.
| File | Description |
|---|---|
ios/PagerView.swift |
Applies scrolling and overdrag settings to outer and embedded paging views. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
On iOS 15 SwiftUI implements `.tabViewStyle(.page)` with a compositional
layout that pages orthogonally: the horizontal paging is performed by an
embedded `UIScrollView` subview of the collection view
(`_UICollectionViewOrthogonalScrollerEmbeddedScrollView`), while the
collection view itself only scrolls vertically. `PagerView` can only toggle
the collection view, so on iOS 15 a pager with `scrollEnabled={false}` could
still be swiped even though the prop reached the native view (the outer
`isScrollEnabled` is `false` while the embedded paging scroll view keeps
`isScrollEnabled = true` and an enabled pan gesture). `overdrag` had the same
problem: `bounces` never reached the view that actually scrolls.
Mirror both values onto the scroll views SwiftUI embedded in the paging
collection view. The traversal stops at `UICollectionViewCell` boundaries so
scroll views belonging to the pages' React Native content are never touched.
On iOS 16 and later the collection view itself is the pager and none of this
is needed, so the whole workaround is isolated in the new
`PagerViewIOS15Compat.swift` and every entry point starts with
`if #available(iOS 16, *) { return }`. Deleting that file and its two call
sites in `PagerView.swift` is all that is required once iOS 15 support is
dropped.
Refs callstack#1028
227b0af to
18c93fa
Compare
Done — the iOS 15 part is now isolated and gated. |
Summary
Fixes the remaining iOS 15 case of #1028: with
scrollEnabled={false}the pager can still be swiped by the user.Why it only happens on iOS 15. SwiftUI implements
.tabViewStyle(.page)with a compositional layout that pages orthogonally. On iOS 15 the actual horizontal paging is performed by an embeddedUIScrollViewsubview of the collection view (_UICollectionViewOrthogonalScrollerEmbeddedScrollView), while the collection view itself only scrolls vertically.PagerViewappliedisScrollEnabled/bouncesonly to the collection view, so the outer view was correctly disabled while the view that really handles the swipe stayed enabled. Measured on an iOS 15.2 simulator withscrollEnabled={false}:isScrollEnabledpanGestureRecognizer.isEnabledcontentSize.widthPagingCollectionView(UICollectionView)00_UICollectionViewOrthogonalScrollerEmbeddedScrollView11PagerViewProvider.scrollEnabledis0as well, i.e. the prop does reach the native view — it just never reaches the scroll view that pages. On iOS 16+ the embedded scroll view does not exist and the collection view itself is the pager (contentSize.width = 804on iOS 18.5), which is why disabling it was enough there.This is a different failure mode from #1071 (initial-value timing /
.onAppear); with 9.0.4 the outer collection view is already disabled, so the iOS 15 report in #1028 is still reproducible.applyScrollEnabled(_:)/applyOverdrag(_:)now forward the values to the collection view and to the paging scroll views embedded in it. The traversal stops atUICollectionViewCellboundaries, so scroll views belonging to the pages' React Native content (FlatList/ScrollViewinside a page) are never touched. All four call sites (introspect,onAppear, and the twoonChangehandlers) go through the new helpers.scrollEnabled,overdrag). No API, JS or typing change. On iOS versions where no embedded scroll view exists, behaviour is unchanged.overdraggets the same treatment for the same reason:bounceswas only applied to the collection view, so over-drag stayed enabled on iOS 15 even with the defaultoverdrag={false}.Test Plan
What's required for testing (prerequisites)?
TabViewno longer uses an embedded paging scroll view there.bun install && bun bootstrap, thenbun example:ios.What are the steps to reproduce (after prerequisites)?
bun example:iosand open the Basic example.scrollEnabled={false};example/src/component/NavigationPanel/ControlPanel.tsx).setPage) still work.Optional, to check the mechanism without relying on gestures — attach lldb and read the paging scroll views (the embedded one is visible via
recursiveDescription):$sv=_UICollectionViewOrthogonalScrollerEmbeddedScrollView. Before:1/1. After:0/0. (UIScrollView.isScrollEnabled = falsealso disables its pan gesture recognizer, so nothing can scroll it any more.)I also confirmed with the same probe, on iOS 15.2 and iOS 18.5:
scrollEnabled={true}re-enables both scroll views at runtime (.onChangepath) — no regression, the pager is not permanently locked;[RNCPagerViewComponentView setPage:1]movescontentOffset.xto the next page);ScrollView/FlatListinside a page keeps its own scrolling (the traversal skipsUICollectionViewCells).Compatibility
Android is unaffected by this code path and already respects
scrollEnabled.Checklist
README.mdRefs #1028