mirror of
https://github.com/status-im/react-native.git
synced 2025-01-26 09:19:10 +00:00
Add velocity to onScrollEndDrag event
Reviewed By: achen1 Differential Revision: D5330215 fbshipit-source-id: e45a302b325c38294324f4f384a5604355dc05aa
This commit is contained in:
parent
75eb55096e
commit
f954f3d9b6
@ -22,8 +22,13 @@ public class OnScrollDispatchHelper {
|
||||
|
||||
private int mPrevX = Integer.MIN_VALUE;
|
||||
private int mPrevY = Integer.MIN_VALUE;
|
||||
private float mXFlingVelocity = 0;
|
||||
private float mYFlingVelocity = 0;
|
||||
|
||||
private long mLastScrollEventTimeMs = -(MIN_EVENT_SEPARATION_MS + 1);
|
||||
|
||||
private static final float THRESHOLD = 0.1f; // Threshold for end fling
|
||||
|
||||
/**
|
||||
* Call from a ScrollView in onScrollChanged, returns true if this onScrollChanged is legit (not a
|
||||
* duplicate) and should be dispatched.
|
||||
@ -35,10 +40,28 @@ public class OnScrollDispatchHelper {
|
||||
mPrevX != x ||
|
||||
mPrevY != y;
|
||||
|
||||
// Skip the first calculation in each scroll
|
||||
if (Math.abs(mXFlingVelocity) < THRESHOLD && Math.abs(mYFlingVelocity) < THRESHOLD) {
|
||||
shouldDispatch = false;
|
||||
}
|
||||
|
||||
if (eventTime - mLastScrollEventTimeMs != 0) {
|
||||
mXFlingVelocity = (float) (x - mPrevX) / (eventTime - mLastScrollEventTimeMs);
|
||||
mYFlingVelocity = (float) (y - mPrevY) / (eventTime - mLastScrollEventTimeMs);
|
||||
}
|
||||
|
||||
mLastScrollEventTimeMs = eventTime;
|
||||
mPrevX = x;
|
||||
mPrevY = y;
|
||||
|
||||
return shouldDispatch;
|
||||
}
|
||||
|
||||
public float getXFlingVelocity() {
|
||||
return this.mXFlingVelocity;
|
||||
}
|
||||
|
||||
public float getYFlingVelocity() {
|
||||
return this.mYFlingVelocity;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
ReactClippingViewGroup {
|
||||
|
||||
private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
|
||||
private final VelocityHelper mVelocityHelper = new VelocityHelper();
|
||||
|
||||
private boolean mActivelyScrolling;
|
||||
private @Nullable Rect mClippingRect;
|
||||
@ -117,7 +118,10 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
|
||||
mActivelyScrolling = true;
|
||||
|
||||
ReactScrollViewHelper.emitScrollEvent(this);
|
||||
ReactScrollViewHelper.emitScrollEvent(
|
||||
this,
|
||||
mOnScrollDispatchHelper.getXFlingVelocity(),
|
||||
mOnScrollDispatchHelper.getYFlingVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,14 +148,19 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
|
||||
return false;
|
||||
}
|
||||
|
||||
mVelocityHelper.calculateVelocity(ev);
|
||||
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (action == MotionEvent.ACTION_UP && mDragging) {
|
||||
ReactScrollViewHelper.emitScrollEndDragEvent(this);
|
||||
ReactScrollViewHelper.emitScrollEndDragEvent(
|
||||
this,
|
||||
mVelocityHelper.getXVelocity(),
|
||||
mVelocityHelper.getYVelocity());
|
||||
mDragging = false;
|
||||
// After the touch finishes, we may need to do some scrolling afterwards either as a result
|
||||
// of a fling or because we need to page align the content
|
||||
handlePostTouchScrolling();
|
||||
}
|
||||
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
|
||||
private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
|
||||
private final OverScroller mScroller;
|
||||
private final VelocityHelper mVelocityHelper = new VelocityHelper();
|
||||
|
||||
private @Nullable Rect mClippingRect;
|
||||
private boolean mDoneFlinging;
|
||||
@ -164,7 +165,10 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
mDoneFlinging = false;
|
||||
}
|
||||
|
||||
ReactScrollViewHelper.emitScrollEvent(this);
|
||||
ReactScrollViewHelper.emitScrollEvent(
|
||||
this,
|
||||
mOnScrollDispatchHelper.getXFlingVelocity(),
|
||||
mOnScrollDispatchHelper.getYFlingVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,12 +195,17 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
|
||||
return false;
|
||||
}
|
||||
|
||||
mVelocityHelper.calculateVelocity(ev);
|
||||
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (action == MotionEvent.ACTION_UP && mDragging) {
|
||||
ReactScrollViewHelper.emitScrollEndDragEvent(this);
|
||||
ReactScrollViewHelper.emitScrollEndDragEvent(
|
||||
this,
|
||||
mVelocityHelper.getXVelocity(),
|
||||
mVelocityHelper.getYVelocity());
|
||||
mDragging = false;
|
||||
disableFpsListener();
|
||||
}
|
||||
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
|
@ -29,16 +29,19 @@ public class ReactScrollViewHelper {
|
||||
/**
|
||||
* Shared by {@link ReactScrollView} and {@link ReactHorizontalScrollView}.
|
||||
*/
|
||||
public static void emitScrollEvent(ViewGroup scrollView) {
|
||||
emitScrollEvent(scrollView, ScrollEventType.SCROLL);
|
||||
public static void emitScrollEvent(ViewGroup scrollView, float xVelocity, float yVelocity) {
|
||||
emitScrollEvent(scrollView, ScrollEventType.SCROLL, xVelocity, yVelocity);
|
||||
}
|
||||
|
||||
public static void emitScrollBeginDragEvent(ViewGroup scrollView) {
|
||||
emitScrollEvent(scrollView, ScrollEventType.BEGIN_DRAG);
|
||||
}
|
||||
|
||||
public static void emitScrollEndDragEvent(ViewGroup scrollView) {
|
||||
emitScrollEvent(scrollView, ScrollEventType.END_DRAG);
|
||||
public static void emitScrollEndDragEvent(
|
||||
ViewGroup scrollView,
|
||||
float xVelocity,
|
||||
float yVelocity) {
|
||||
emitScrollEvent(scrollView, ScrollEventType.END_DRAG, xVelocity, yVelocity);
|
||||
}
|
||||
|
||||
public static void emitScrollMomentumBeginEvent(ViewGroup scrollView) {
|
||||
@ -50,6 +53,14 @@ public class ReactScrollViewHelper {
|
||||
}
|
||||
|
||||
private static void emitScrollEvent(ViewGroup scrollView, ScrollEventType scrollEventType) {
|
||||
emitScrollEvent(scrollView, scrollEventType, 0, 0);
|
||||
}
|
||||
|
||||
private static void emitScrollEvent(
|
||||
ViewGroup scrollView,
|
||||
ScrollEventType scrollEventType,
|
||||
float xVelocity,
|
||||
float yVelocity) {
|
||||
View contentView = scrollView.getChildAt(0);
|
||||
|
||||
if (contentView == null) {
|
||||
@ -63,6 +74,8 @@ public class ReactScrollViewHelper {
|
||||
scrollEventType,
|
||||
scrollView.getScrollX(),
|
||||
scrollView.getScrollY(),
|
||||
xVelocity,
|
||||
yVelocity,
|
||||
contentView.getWidth(),
|
||||
contentView.getHeight(),
|
||||
scrollView.getWidth(),
|
||||
|
@ -32,6 +32,8 @@ public class ScrollEvent extends Event<ScrollEvent> {
|
||||
|
||||
private int mScrollX;
|
||||
private int mScrollY;
|
||||
private double mXVelocity;
|
||||
private double mYVelocity;
|
||||
private int mContentWidth;
|
||||
private int mContentHeight;
|
||||
private int mScrollViewWidth;
|
||||
@ -43,6 +45,8 @@ public class ScrollEvent extends Event<ScrollEvent> {
|
||||
ScrollEventType scrollEventType,
|
||||
int scrollX,
|
||||
int scrollY,
|
||||
float xVelocity,
|
||||
float yVelocity,
|
||||
int contentWidth,
|
||||
int contentHeight,
|
||||
int scrollViewWidth,
|
||||
@ -56,6 +60,8 @@ public class ScrollEvent extends Event<ScrollEvent> {
|
||||
scrollEventType,
|
||||
scrollX,
|
||||
scrollY,
|
||||
xVelocity,
|
||||
yVelocity,
|
||||
contentWidth,
|
||||
contentHeight,
|
||||
scrollViewWidth,
|
||||
@ -76,6 +82,8 @@ public class ScrollEvent extends Event<ScrollEvent> {
|
||||
ScrollEventType scrollEventType,
|
||||
int scrollX,
|
||||
int scrollY,
|
||||
float xVelocity,
|
||||
float yVelocity,
|
||||
int contentWidth,
|
||||
int contentHeight,
|
||||
int scrollViewWidth,
|
||||
@ -84,6 +92,8 @@ public class ScrollEvent extends Event<ScrollEvent> {
|
||||
mScrollEventType = scrollEventType;
|
||||
mScrollX = scrollX;
|
||||
mScrollY = scrollY;
|
||||
mXVelocity = xVelocity;
|
||||
mYVelocity = yVelocity;
|
||||
mContentWidth = contentWidth;
|
||||
mContentHeight = contentHeight;
|
||||
mScrollViewWidth = scrollViewWidth;
|
||||
@ -134,11 +144,16 @@ public class ScrollEvent extends Event<ScrollEvent> {
|
||||
layoutMeasurement.putDouble("width", PixelUtil.toDIPFromPixel(mScrollViewWidth));
|
||||
layoutMeasurement.putDouble("height", PixelUtil.toDIPFromPixel(mScrollViewHeight));
|
||||
|
||||
WritableMap velocity = Arguments.createMap();
|
||||
velocity.putDouble("x", mXVelocity);
|
||||
velocity.putDouble("y", mYVelocity);
|
||||
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putMap("contentInset", contentInset);
|
||||
event.putMap("contentOffset", contentOffset);
|
||||
event.putMap("contentSize", contentSize);
|
||||
event.putMap("layoutMeasurement", layoutMeasurement);
|
||||
event.putMap("velocity", velocity);
|
||||
|
||||
event.putInt("target", getViewTag());
|
||||
event.putBoolean("responderIgnoreScroll", true);
|
||||
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.scroll;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
|
||||
/**
|
||||
* This Class helps to calculate the velocity for all ScrollView. The x and y velocity
|
||||
* will later on send to ReactScrollViewHelper for further use.
|
||||
*
|
||||
*/
|
||||
public class VelocityHelper {
|
||||
|
||||
private @Nullable VelocityTracker mVelocityTracker;
|
||||
private float mXVelocity;
|
||||
private float mYVelocity;
|
||||
|
||||
/**
|
||||
* Call from a ScrollView in onTouchEvent.
|
||||
* Calculating the velocity for END_DRAG movement and send them back to react ScrollResponder.js
|
||||
* */
|
||||
public void calculateVelocity(MotionEvent ev) {
|
||||
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (mVelocityTracker == null) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
}
|
||||
mVelocityTracker.addMovement(ev);
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL: {
|
||||
// Calculate velocity on END_DRAG
|
||||
mVelocityTracker.computeCurrentVelocity(1); // points/millisecond
|
||||
mXVelocity = mVelocityTracker.getXVelocity();
|
||||
mYVelocity = mVelocityTracker.getYVelocity();
|
||||
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Needs to call ACTION_UP/CANCEL to update the mXVelocity */
|
||||
public float getXVelocity() {
|
||||
return mXVelocity;
|
||||
}
|
||||
|
||||
/* Needs to call ACTION_UP/CANCEL to update the mYVelocity */
|
||||
public float getYVelocity() {
|
||||
return mYVelocity;
|
||||
}
|
||||
}
|
@ -836,11 +836,12 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
|
||||
ScrollEventType.SCROLL,
|
||||
horiz,
|
||||
vert,
|
||||
0f, // can't get x velocity
|
||||
0f, // can't get y velocity
|
||||
0, // can't get content width
|
||||
0, // can't get content height
|
||||
mReactEditText.getWidth(),
|
||||
mReactEditText.getHeight()
|
||||
);
|
||||
mReactEditText.getHeight());
|
||||
|
||||
mEventDispatcher.dispatchEvent(event);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user