-
Notifications
You must be signed in to change notification settings - Fork 25k
Description
Description
It does not seem like contentInset or contentOffset is reset when prepareForRecyle is run on ScrollViews on iOS for New Architecture.
This is most noticeable when using centerContent={true} on ScrollViews with some height and not much content. If you unmount such a ScrollView, and mount another with small height (like a horizontal ScrollView in my example here), you will notice the content in the horizontal one is displaced quite a bit.
This is because the native RCTEnhancedScrollView is recycled between those mounts, and the inset and offset is re-used (see logs and video). This is not a problem on the old architecture.
If I apply a patch to actually recalculate the content inset on recycle this is fixed: e3e2bb1
Admittedly it is kind of hacky, so do not think this is a good and proper fix.
Steps to reproduce
- Use the RNTester-app with this reproducer
- Click
Playgroundtab, and see that low-height horizontal ScrollView is at the top (as it should be). - Click
Vertical ScrollView With Centered Content-button, and notice that the content of vertical scroll view is at top (and not centered), which is a bug. - Click
Low Height Horizontal Scroll-button, and notice that now the low-height horizontal ScrollView is further down on the screen. Also a bug.
React Native Version
0.83.1
Affected Platforms
Runtime - iOS
Areas
Fabric - The New Renderer
Output of npx @react-native-community/cli info
System:
OS: macOS 15.6.1
CPU: (10) arm64 Apple M1 Pro
Memory: 1.17 GB / 32.00 GB
Shell:
version: 4.0.2
path: /opt/homebrew/bin/fish
Binaries:
Node:
version: 22.17.1
path: /usr/local/bin/node
Yarn:
version: 1.22.22
path: /opt/homebrew/bin/yarn
npm:
version: 10.9.2
path: /usr/local/bin/npm
Watchman:
version: 2025.08.11.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.15.2
path: /Users/cb/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.1
- iOS 26.1
- macOS 26.1
- tvOS 26.1
- visionOS 26.1
- watchOS 26.1
Android SDK:
API Levels:
- "31"
- "34"
- "35"
- "36"
Build Tools:
- 34.0.0
- 35.0.0
- 36.0.0
System Images:
- android-35 | Google APIs ARM 64 v8a
- android-35 | Google Play ARM 64 v8a
- android-35 | Pre-Release 16 KB Page Size Google Play ARM 64 v8a
- android-36 | Google APIs ARM 64 v8a
- android-36 | Google Play ARM 64 v8a
- android-36 | Pre-Release 16 KB Page Size Google Play ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: 2025.1 AI-251.26094.121.2512.13930704
Xcode:
version: 26.1.1/17B100
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.16
path: /usr/bin/javac
Ruby:
version: 3.2.0
path: /Users/cb/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli": Not Found
react: Not Found
react-native: Not Found
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: false
newArchEnabled: false
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
If I capture view hierarchy in Xcode, at first the horizontal ScrollView has this state:
<RCTEnhancedScrollView: 0x10cdc0e00; baseClass = UIScrollView; frame = (0 0; 382 661.333); clipsToBounds = YES;
autoresize = W+H; gestureRecognizers = <NSArray: 0x600000d95e90>; layer = <CALayer: 0x600000d96220>;
contentOffset: {0, 0}; contentSize: {200, 20}; adjustedContentInset: {0, 0, 0, 0} topEdge=<style=automatic backgroundCapture=color>>
Note the inset and offset: contentOffset: {0, 0}; contentSize: {200, 20}; adjustedContentInset: {0, 0, 0, 0}
If I navigate to the taller vertical ScrollView (and capture), it has this state:
<RCTEnhancedScrollView: 0x10cdc0e00; baseClass = UIScrollView; frame = (0 0; 382 661.333); clipsToBounds = YES;
autoresize = W+H; gestureRecognizers = <NSArray: 0x600000d95e90>; layer = <CALayer: 0x600000d96220>;
contentOffset: {0, 0}; contentSize: {382, 300}; adjustedContentInset: {0, 0, 0, 0} topEdge=<style=automatic backgroundCapture=color>>
Here the offset and inset is actually wrong, since it is supposed to center the content in the screen: contentOffset: {0, 0}; contentSize: {382, 300}; adjustedContentInset: {0, 0, 0, 0}
It has "inherited" those from the horizontal ScrollView. If I navigate back to the horizontal ScrollView:
<RCTEnhancedScrollView: 0x10cdc0e00; baseClass = UIScrollView; frame = (0 0; 382 661.333); clipsToBounds = YES;
autoresize = W+H; gestureRecognizers = <NSArray: 0x600000d95e90>; layer = <CALayer: 0x600000d96220>;
contentOffset: {0, -180.66666666666666}; contentSize: {200, 20}; adjustedContentInset: {180.66666666666663, 0, 180.66666666666663, 0} topEdge=<style=automatic backgroundCapture=color>>
Now these are wrong: contentOffset: {0, -180.66666666666666}; contentSize: {200, 20}; adjustedContentInset: {180.66666666666663, 0, 180.66666666666663, 0}
It has actually inherited the "center content" offset/inset from the vertical ScrollView.
On next navigate back to vertical, the content is properly centered for that ScrollView, but wrong going forward for the horizontal one.
Notice the pointer 0x10cdc0e00 is the same for all instances, so it actually recycled the same native ScrollView.