diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index 5d5d67f3ff4..ac8c27c1d8a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -18,7 +18,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -48,7 +47,6 @@ import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.events.NativeGestureUtil; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasFlingAnimator; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasScrollState; -import com.facebook.react.views.scroll.ReactScrollViewHelper.ReactScrollViewScrollDirection; import com.facebook.react.views.scroll.ReactScrollViewHelper.ReactScrollViewScrollState; import com.facebook.react.views.view.ReactViewBackgroundManager; import java.lang.reflect.Field; @@ -141,8 +139,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView new ReactScrollViewScrollState( I18nUtil.getInstance().isRTL(context) ? ViewCompat.LAYOUT_DIRECTION_RTL - : ViewCompat.LAYOUT_DIRECTION_LTR, - ReactScrollViewScrollDirection.HORIZONTAL); + : ViewCompat.LAYOUT_DIRECTION_LTR); } @Nullable @@ -814,10 +811,13 @@ public class ReactHorizontalScrollView extends HorizontalScrollView // predict where a fling would end up so we can scroll to the nearest snap offset int maximumOffset = Math.max(0, computeHorizontalScrollRange() - getWidth()); int width = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this); - Point postAnimationScroll = ReactScrollViewHelper.getPostAnimationScroll(this, velocityX > 0); scroller.fling( - postAnimationScroll.x, // startX - postAnimationScroll.y, // startY + ReactScrollViewHelper.getNextFlingStartValue( + this, + getScrollX(), + getReactScrollViewScrollState().getFinalAnimatedPositionScroll().x, + velocityX > 0), // startX + getScrollY(), // startY velocityX, // velocityX 0, // velocityY 0, // minX @@ -842,7 +842,12 @@ public class ReactHorizontalScrollView extends HorizontalScrollView double interval = (double) getSnapInterval(); double currentOffset = - (double) (ReactScrollViewHelper.getPostAnimationScroll(this, velocity > 0).x); + (double) + (ReactScrollViewHelper.getNextFlingStartValue( + this, + getScrollX(), + getReactScrollViewScrollState().getFinalAnimatedPositionScroll().x, + velocity > 0)); double targetOffset = (double) predictFinalScrollPosition(velocity); int previousPage = (int) Math.floor(currentOffset / interval); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index 044103c7cdb..1b025432c1c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -18,7 +18,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -44,7 +43,6 @@ import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.events.NativeGestureUtil; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasFlingAnimator; import com.facebook.react.views.scroll.ReactScrollViewHelper.HasScrollState; -import com.facebook.react.views.scroll.ReactScrollViewHelper.ReactScrollViewScrollDirection; import com.facebook.react.views.scroll.ReactScrollViewHelper.ReactScrollViewScrollState; import com.facebook.react.views.view.ReactViewBackgroundManager; import java.lang.reflect.Field; @@ -102,8 +100,7 @@ public class ReactScrollView extends ScrollView private int pendingContentOffsetY = UNSET_CONTENT_OFFSET; private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager(); private final ReactScrollViewScrollState mReactScrollViewScrollState = - new ReactScrollViewScrollState( - ViewCompat.LAYOUT_DIRECTION_LTR, ReactScrollViewScrollDirection.VERTICAL); + new ReactScrollViewScrollState(ViewCompat.LAYOUT_DIRECTION_LTR); private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollY", 0, 0); public ReactScrollView(Context context) { @@ -603,10 +600,13 @@ public class ReactScrollView extends ScrollView // predict where a fling would end up so we can scroll to the nearest snap offset int maximumOffset = getMaxScrollY(); int height = getHeight() - getPaddingBottom() - getPaddingTop(); - Point postAnimationScroll = ReactScrollViewHelper.getPostAnimationScroll(this, velocityY > 0); scroller.fling( - postAnimationScroll.x, // startX - postAnimationScroll.y, // startY + getScrollX(), // startX + ReactScrollViewHelper.getNextFlingStartValue( + this, + getScrollY(), + getReactScrollViewScrollState().getFinalAnimatedPositionScroll().y, + velocityY > 0), // startY 0, // velocityX velocityY, // velocityY 0, // minX @@ -631,7 +631,12 @@ public class ReactScrollView extends ScrollView private void smoothScrollAndSnap(int velocity) { double interval = (double) getSnapInterval(); double currentOffset = - (double) (ReactScrollViewHelper.getPostAnimationScroll(this, velocity > 0).y); + (double) + (ReactScrollViewHelper.getNextFlingStartValue( + this, + getScrollY(), + getReactScrollViewScrollState().getFinalAnimatedPositionScroll().y, + velocity > 0)); double targetOffset = (double) predictFinalScrollPosition(velocity); int previousPage = (int) Math.floor(currentOffset / interval); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java index 03238555f2b..018a719084e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java @@ -215,24 +215,16 @@ public class ReactScrollViewHelper { sScrollListeners.remove(listener); } - public enum ReactScrollViewScrollDirection { - HORIZONTAL, - VERTICAL, - } - public static class ReactScrollViewScrollState { private final int mLayoutDirection; - private final ReactScrollViewScrollDirection mScrollDirection; private final Point mFinalAnimatedPositionScroll = new Point(); private int mScrollAwayPaddingTop = 0; private final Point mLastStateUpdateScroll = new Point(-1, -1); private boolean mIsCanceled = false; private boolean mIsFinished = true; - public ReactScrollViewScrollState( - final int layoutDirection, final ReactScrollViewScrollDirection scrollDirection) { + public ReactScrollViewScrollState(final int layoutDirection) { mLayoutDirection = layoutDirection; - mScrollDirection = scrollDirection; } /** @@ -243,14 +235,6 @@ public class ReactScrollViewHelper { return mLayoutDirection; } - /** - * Get the scroll direction. Can be either ReactScrollViewScrollDirection.HORIZONTAL or - * ReactScrollViewScrollDirection.VERTICAL. - */ - public ReactScrollViewScrollDirection getScrollDirection() { - return mScrollDirection; - } - /** Get the position after current animation is finished */ public Point getFinalAnimatedPositionScroll() { return mFinalAnimatedPositionScroll; @@ -334,43 +318,32 @@ public class ReactScrollViewHelper { final int scrollX = scrollView.getScrollX(); final int scrollY = scrollView.getScrollY(); - final ReactScrollViewScrollDirection scrollDirection = scrollState.getScrollDirection(); - if (scrollDirection == ReactScrollViewScrollDirection.HORIZONTAL && scrollX != x) { + // Only one fling animator will be started. For the horizontal scroll view, scrollY will always + // be the same to y. This is the same to the vertical scroll view. + if (scrollX != x) { scrollView.startFlingAnimator(scrollX, x); } - if (scrollDirection == ReactScrollViewScrollDirection.VERTICAL && scrollY != y) { + if (scrollY != y) { scrollView.startFlingAnimator(scrollY, y); } updateFabricScrollState(scrollView, x, y); } - /** Get current (x, y) position or position after current animation finishes, if any. */ + /** Get current position or position after current animation finishes, if any. */ public static < T extends ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState & HasFlingAnimator> - Point getPostAnimationScroll(final T scrollView, final boolean isPositiveVelocity) { + int getNextFlingStartValue( + final T scrollView, + final int currentValue, + final int postAnimationValue, + final boolean isPositiveVelocity) { final ReactScrollViewScrollState scrollState = scrollView.getReactScrollViewScrollState(); final int velocityDirectionMask = isPositiveVelocity ? 1 : -1; - final Point animatedScrollPos = scrollState.getFinalAnimatedPositionScroll(); - final Point currentScrollPos = new Point(scrollView.getScrollX(), scrollView.getScrollY()); - - boolean isMovingTowardsAnimatedValue = false; - switch (scrollState.getScrollDirection()) { - case HORIZONTAL: - isMovingTowardsAnimatedValue = - velocityDirectionMask * (animatedScrollPos.x - currentScrollPos.x) > 0; - break; - - case VERTICAL: - isMovingTowardsAnimatedValue = - velocityDirectionMask * (animatedScrollPos.y - currentScrollPos.y) > 0; - break; - - default: - throw new IllegalArgumentException("ScrollView has unexpected scroll direction."); - } + final boolean isMovingTowardsAnimatedValue = + velocityDirectionMask * (postAnimationValue - currentValue) > 0; // When the fling animation is not finished, or it was canceled and now we are moving towards // the final animated value, we will return the final animated value. This is because follow up @@ -378,8 +351,8 @@ public class ReactScrollViewHelper { // scrolls are still working. return !scrollState.getIsFinished() || (scrollState.getIsCanceled() && isMovingTowardsAnimatedValue) - ? animatedScrollPos - : currentScrollPos; + ? postAnimationValue + : currentValue; } public static <