mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Support override predict final scroll position with custom fling animator
Summary: This diff add custom prediction for fling distance support. This is needed for customize fling animator to calculate predicted fling distance, instead of using the overscroller that may not be used by the animator. More context on this -- when fling happens, our code will first predict the final fling position `p`, apply the snapping logic to decide the expected snapping position `pSnapping` given `p`, scroll velocity and children layout, then trigger the overscroller (existing) or custom fling animator to finish the fling. Currently, the prediction logic is done with overscroller, and custom fling animator has no control over how the predicted fling distance should be. Changes in this diff allow the animator to override `getExtrapolatedDistance` method and provide that information. Changelog: [Android][Added] - Add new API for custom fling animator to provide predicted travel distance for its fling animation. Reviewed By: mdvacca Differential Revision: D32571734 fbshipit-source-id: d34b969206f8b6cb5c68d2f50a18749bfebbc97e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
39a35feff7
commit
fe6277a30d
+19
-1
@@ -803,7 +803,16 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
private int predictFinalScrollPosition(int velocityX) {
|
||||
// predict where a fling would end up so we can scroll to the nearest snap offset
|
||||
final int maximumOffset = Math.max(0, computeHorizontalScrollRange() - getWidth());
|
||||
return ReactScrollViewHelper.predictFinalScrollPosition(this, velocityX, 0, maximumOffset, 0).x;
|
||||
// TODO(T106335409): Existing prediction still uses overscroller. Consider change this to use
|
||||
// fling animator instead.
|
||||
return getFlingAnimator() == DEFAULT_FLING_ANIMATOR
|
||||
? ReactScrollViewHelper.predictFinalScrollPosition(this, velocityX, 0, maximumOffset, 0).x
|
||||
: ReactScrollViewHelper.getNextFlingStartValue(
|
||||
this,
|
||||
getScrollX(),
|
||||
getReactScrollViewScrollState().getFinalAnimatedPositionScroll().x,
|
||||
velocityX)
|
||||
+ getFlingExtrapolatedDistance(velocityX);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1224,4 +1233,13 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
public ValueAnimator getFlingAnimator() {
|
||||
return DEFAULT_FLING_ANIMATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFlingExtrapolatedDistance(int velocityX) {
|
||||
// The DEFAULT_FLING_ANIMATOR uses AccelerateDecelerateInterpolator, which is not depending on
|
||||
// the init velocity. We use the overscroller to decide the fling distance.
|
||||
return ReactScrollViewHelper.predictFinalScrollPosition(
|
||||
this, velocityX, 0, Math.max(0, computeHorizontalScrollRange() - getWidth()), 0)
|
||||
.x;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,8 +591,16 @@ public class ReactScrollView extends ScrollView
|
||||
|
||||
private int predictFinalScrollPosition(int velocityY) {
|
||||
// predict where a fling would end up so we can scroll to the nearest snap offset
|
||||
return ReactScrollViewHelper.predictFinalScrollPosition(this, 0, velocityY, 0, getMaxScrollY())
|
||||
.y;
|
||||
// TODO(T106335409): Existing prediction still uses overscroller. Consider change this to use
|
||||
// fling animator instead.
|
||||
return getFlingAnimator() == DEFAULT_FLING_ANIMATOR
|
||||
? ReactScrollViewHelper.predictFinalScrollPosition(this, 0, velocityY, 0, getMaxScrollY()).y
|
||||
: ReactScrollViewHelper.getNextFlingStartValue(
|
||||
this,
|
||||
getScrollY(),
|
||||
getReactScrollViewScrollState().getFinalAnimatedPositionScroll().y,
|
||||
velocityY)
|
||||
+ getFlingExtrapolatedDistance(velocityY);
|
||||
}
|
||||
|
||||
private View getContentView() {
|
||||
@@ -1088,4 +1096,12 @@ public class ReactScrollView extends ScrollView
|
||||
public ValueAnimator getFlingAnimator() {
|
||||
return DEFAULT_FLING_ANIMATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFlingExtrapolatedDistance(int velocityY) {
|
||||
// The DEFAULT_FLING_ANIMATOR uses AccelerateDecelerateInterpolator, which is not depending on
|
||||
// the init velocity. We use the overscroller to decide the fling distance.
|
||||
return ReactScrollViewHelper.predictFinalScrollPosition(this, 0, velocityY, 0, getMaxScrollY())
|
||||
.y;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -510,10 +510,10 @@ public class ReactScrollViewHelper {
|
||||
& HasFlingAnimator>
|
||||
Point predictFinalScrollPosition(
|
||||
final T scrollView,
|
||||
int velocityX,
|
||||
int velocityY,
|
||||
int maximumOffsetX,
|
||||
int maximumOffsetY) {
|
||||
final int velocityX,
|
||||
final int velocityY,
|
||||
final int maximumOffsetX,
|
||||
final int maximumOffsetY) {
|
||||
final ReactScrollViewScrollState scrollState = scrollView.getReactScrollViewScrollState();
|
||||
// ScrollView can *only* scroll for 250ms when using smoothScrollTo and there's
|
||||
// no way to customize the scroll duration. So, we create a temporary OverScroller
|
||||
@@ -566,5 +566,8 @@ public class ReactScrollViewHelper {
|
||||
|
||||
/** Get the fling animator that is reused for the ScrollView to handle fling animation. */
|
||||
ValueAnimator getFlingAnimator();
|
||||
|
||||
/** Get the fling distance with current velocity for prediction */
|
||||
int getFlingExtrapolatedDistance(int velocity);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user