Conversation
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` toggled
`isScrollEnabled` and `bounces` on the collection view only, so on iOS 15 a
pager with `scrollEnabled={false}` could still be swiped even though the prop
did reach the native view (outer `isScrollEnabled` is `false`, the embedded
paging scroll view keeps `isScrollEnabled = true` and an enabled pan gesture).
Apply both values to the embedded paging scroll views as well. The traversal
stops at `UICollectionViewCell` boundaries so scroll views belonging to the
pages' React Native content are never touched. On iOS 16+ the embedded scroll
view does not exist and the collection view itself is the pager, so behaviour
there is unchanged.
This also makes `overdrag` work on iOS 15 for the same reason: `bounces` was
only applied to the collection view, leaving over-drag enabled.
Refs callstack#1028
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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