Refactor helper method for ScrollView to not detect scroll direction

Summary:
The helper class for ScrollView should not need to detect the scroll direction. If it has to do so, that means the corresponding logic should live in the `ReactScrollView` or `ReactHorizontalScrollView` respectively.

This diff is to remove the scroll direction detection logic from the scroll view helper. Long term we should keep it this way as the shared code got moved to the helper class from the scroll view classes.

Changelog:
[Internal]

Reviewed By: javache

Differential Revision: D32514429

fbshipit-source-id: 2165f2eba90cc25d14834c39148fe8ce8805bea6
This commit is contained in:
Xin Chen 2021-11-30 13:13:05 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 8ab2cbb78f
Коммит 508de3f351
3 изменённых файлов: 41 добавлений и 58 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 <