Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement maintainVisibleContentPosition #2588

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

janicduplessis
Copy link
Contributor

This implements the maintainVisibleContentPosition prop on ScrollView (https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition), as well as normalizing the scrolling behavior when adding items at the top of a ScrollView.

Currently the behavior varies depending on the browser. In Chrome the content position is maintained if the scroll position is > 0, while on Safari it is never maintained. The Chrome behavior diverges from react-native so this also makes sure it is consistent, which is that by default the content position is not maintained, and that when the maintainVisibleContentPosition prop is set it is.

The general logic is adapted from the iOS implementation in react-native (https://github.com/facebook/react-native/blob/main/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm#L723-L787). The general idea is to get the position of the first visible view before changes to the view hierarchy, compare it to its position after the changes and adjust the scroll position accordingly. In react-native there are UIManager hooks that are executed before / after a transaction is committed. On the web we can use MutationObserver to detect changes to the subtree of the ScrollView, but sadly I don't think there are any way to have a callback executed before the changes are committed so instead we update the first visible view on scroll events.

To fix the Chrome behavior that automatically preserves the scroll position we save the last scroll position from scroll events and reset it to that last value in the MutationObserver callback. This successfully reverts the adjustment Chrome did.

I also updated the example app to include these new features in the ScrollView example.

Here's a few videos of the example before and after the changes

Before

Chrome maintains scroll position when not scrolled at the top, Safari doesn't.

Chrome:

Screen.Recording.2023-10-04.at.19.48.43.mov

Safari:

Screen.Recording.2023-10-04.at.19.57.24.mov

After

Same behavior in Chrome and Safari, shows without mvcp, then with mvcp, then with autoscrollToTopThreshold.

Chrome:

Screen.Recording.2023-10-04.at.20.03.00.mov

Safari:

Screen.Recording.2023-10-04.at.20.01.04.mov

@codesandbox-ci
Copy link

codesandbox-ci bot commented Oct 5, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 73139fa:

Sandbox Source
react-native-web-examples Configuration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant