Skip to content

[iOS] Reset ScrollView frame when recycling - #59362

Open
kirillzyusko wants to merge 1 commit into
react:mainfrom
kirillzyusko:codex/reset-scrollview-frame-on-recycle
Open

kirillzyusko wants to merge 1 commit into
react:mainfrom
kirillzyusko:codex/reset-scrollview-frame-on-recycle

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

An interactive native-stack swipe-back with keyboard dismissal and native-driven Animated height updates can leave the internal UIScrollView with a negative frame origin. prepareForRecycle resets the outer component's frame, but retains the inner view's geometry. Reopening the screen reuses that offset view, shifting its content upward and leaving a gap at the bottom.

Reset _scrollView.frame to self.bounds at the end of prepareForRecycle.

Warning

To reproduce this problem I had to use new experimental shared Animated backend + drive height updates. And also use native-stack. I didn't find a way to reproduce it without react-native-screens/native-stack, but I strongly believe that root cause lives in react-native core.

Minimal runnable reproduction | App.js code | Reproduction changes

The repro uses React Native Animated, native-stack, screens and safe-area-context. It has no Reanimated, Worklets or keyboard-controller dependency (though original problem was discovered with react-native-keyboard-controller (#1200) /react-native-reanimated/react-native-worklets - in this PR I tried to isolate changes as close to bare RN as possible, but I still had to use react-native-screens for native navigation with gestures and all that stuff. Without navigation I didn't find a way to reproduce this problem - but repro confirms that it's not reanimated/keyboard-controlelr specific issue).

The public Experimental release preset enables the shared Animated backend and C++ Native Animated.

Related report: react-native-keyboard-controller#1200.

Changelog:

[IOS] [FIXED] - Reset the inner ScrollView frame when recycling to prevent a stale offset on reuse.

Test Plan:

Verified using iPhone 16 Pro Simulator (iOS 18.5), Xcode 27.0, React Native 0.87.1 / Fabric.

Reproduction

At the pinned reproduction commit:

yarn
bundle install
cd ios && bundle exec pod install && cd ..
yarn start
# In another terminal:
yarn ios --simulator "iPhone 16 Pro"

Enable the simulator's software keyboard. The interpolation constants target this device's 402 × 874 pt screen.

  1. Freshly launch the app.
  2. Press Open ScrollView.
  3. Focus Type a message and wait for the keyboard.
  4. Press Scroll to end.
  5. Swipe back from the left phone bezel, with the keyboard initially open.
  6. Press Open ScrollView again.

Important

The first opening maps native onScroll events to height using Animated.event with useNativeDriver: true. Keyboard dismissal triggers a second resize after 100 ms.

⚠️ The second opening uses a static height to expose the recycled geometry.

Then run yarn apply-fix, rebuild with yarn ios --simulator "iPhone 16 Pro", and repeat the same steps.

Results

After reopening Before After
Inner ScrollView frame.y −128.6667 pt 0 pt
Same native inner and outer views reused Yes Yes
React tag changes on reuse 218 -> 426 218 -> 426
Yellow gap below content Visible Absent

Screenshots — iPhone 16 Pro Simulator, iOS 18.5

Before After
Before — iPhone 16 Pro Simulator, iOS 18.5 After — iPhone 16 Pro Simulator, iOS 18.5

Videos — iPhone 16 Pro Simulator, iOS 18.5

Before After
before.mp4
after-english.mp4

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 22, 2026
@kirillzyusko
kirillzyusko marked this pull request as ready for review October 22, 2026 17:06
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 22, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant