Skip to content

Commit

Permalink
Fix scrollview momentum not stopping on scrollTo/scrollToEnd for hori…
Browse files Browse the repository at this point in the history
…zontal scrollviews (#39529)

Summary:
### Motivation
My main motivation for this is using nested horizontal `Flashlists` inside a vertical `Flashlist`.
Like a `RecyclerView`, since my horizontal lists get recycled, if I scroll say the first horizontal list and scroll down, then when this list gets recycled it continues scrolling even if the content is new:

![nested-list-recycling](https://github.com/facebook/react-native/assets/4534323/f75a2a9b-6ab5-4554-811f-8d85ddfb81de)

To handle this, I want to call `scrollTo` everytime a new row appears to reset the scroll offset, however I've realized this doesn't stop the scroll momentum

### The bug

When scrolling and calling `scrollTo`, scroll momentum should be stopped and we should scroll to where `scrollTo` asked for.
All credit goes to tomekzaw for #36104 who fixed it for vertical scrollviews

I realized we had the same issue for
- horizontal scroll views
- when calling `scrollToEnd`

| Vertical scrollview (working ✅) | Horizontal scrollview (before fix, not stopping ❌) | Horizontal scrollview (after fix ✅)|
|--------|--------|--|
| ![vertical-scrolltoffset-working](https://github.com/facebook/react-native/assets/4534323/884d95ce-9b09-47aa-99a7-99ca579a8fc4)|![horizontal-scrolloffset-bug](https://github.com/facebook/react-native/assets/4534323/0065a9d0-f905-4354-9caa-29a0a1f914ba)|![horizontal-scrolloffset-fixed](https://github.com/facebook/react-native/assets/4534323/ab49c356-23e8-464a-83a9-c4632b9d673e)|

Based on  #38728 I kept all those calls to `abortAnimation` on the View Manager

## Changelog:

[ANDROID] [FIXED] - Fixed horizontal ScrollView momentum not stopping when calling scrollTo programmatically
[ANDROID] [FIXED] - Fixed ScrollView momentum not stopping when calling scrollToEnd programmatically

Pull Request resolved: #39529

Test Plan:
My test code is [this](https://gist.github.com/Almouro/3ffcfbda8e2239e64bee93985e243000)
Basically:
- a scrollview with a few elements
- some buttons to trigger a `scrollTo`

To reproduce the bug, I scroll then click one of the buttons triggering a `scrollTo`

I added `react-native@nightly` to my project, and copy pasted `packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll` folder from this branch to try out my fixes

Then tested the following scenarios on Android:

| List layout  | Method | Not animated | Animated|
|--------|--------|--|--|
| horizontal | scrollTo | ![horizontal-scrollTo-no](https://github.com/facebook/react-native/assets/4534323/bda87a19-43cf-4fe9-9340-f70a3d5cd6a4)| ![horizontal-scrollto-yes](https://github.com/facebook/react-native/assets/4534323/8628d7ff-ee28-4185-81d1-1783f0fd990f) |
| horizontal | scrollToEnd  |![horizontal-scrolltoend-no](https://github.com/facebook/react-native/assets/4534323/594bb539-cb27-4234-8a8f-74d5b2bbe25f) | ![horizontal-scrolltoend-yes](https://github.com/facebook/react-native/assets/4534323/7366abcd-95fb-42ab-89e1-38fd4b10d966)|
| vertical | scrollTo | ![vertical-scrollto-no](https://github.com/facebook/react-native/assets/4534323/54555250-d4df-4bc2-b20f-46c706e8c726)|![vertical-scrollto-yes](https://github.com/facebook/react-native/assets/4534323/0c109f81-0bbd-475b-90f1-f1467317c799) |
| vertical | scrollToEnd  | ![vertical-scrolltoend-no](https://github.com/facebook/react-native/assets/4534323/f48c8196-8f2f-4d98-b750-91c067d1a063) | ![vertical-scrolltoend-yes](https://github.com/facebook/react-native/assets/4534323/04bb06dc-7e20-40de-a40d-e1da1fec491a)|

Reviewed By: javache

Differential Revision: D49437886

Pulled By: ryancat

fbshipit-source-id: 358c9b0eed7dabcbc9b87a15d1a757b414ef514b
  • Loading branch information
Almouro authored and facebook-github-bot committed Sep 20, 2023
1 parent 196b3f9 commit 2f86aaf
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ public void setDecelerationRate(float decelerationRate) {
}
}

public void abortAnimation() {
if (mScroller != null && !mScroller.isFinished()) {
mScroller.abortAnimation();
}
}

public void setSnapInterval(int snapInterval) {
mSnapInterval = snapInterval;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public void flashScrollIndicators(ReactHorizontalScrollView scrollView) {
@Override
public void scrollTo(
ReactHorizontalScrollView scrollView, ReactScrollViewCommandHelper.ScrollToCommandData data) {
scrollView.abortAnimation();
if (data.mAnimated) {
scrollView.reactSmoothScrollTo(data.mDestX, data.mDestY);
} else {
Expand All @@ -219,6 +220,7 @@ public void scrollToEnd(
"scrollToEnd called on HorizontalScrollView without child");
}
int right = child.getWidth() + scrollView.getPaddingRight();
scrollView.abortAnimation();
if (data.mAnimated) {
scrollView.reactSmoothScrollTo(right, scrollView.getScrollY());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ public void scrollToEnd(

// ScrollView always has one child - the scrollable area
int bottom = child.getHeight() + scrollView.getPaddingBottom();
scrollView.abortAnimation();
if (data.mAnimated) {
scrollView.reactSmoothScrollTo(scrollView.getScrollX(), bottom);
} else {
Expand Down

0 comments on commit 2f86aaf

Please sign in to comment.