yeet
This commit is contained in:
28
node_modules/react-native-gesture-handler/android/lib/build.gradle
generated
vendored
Normal file
28
node_modules/react-native-gesture-handler/android/lib/build.gradle
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
repositories {
|
||||
maven { url 'https://repo1.maven.org/maven2' }
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion '25.0.0'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.android.support:appcompat-v7:23.4.0'
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
public abstract class BaseGestureHandlerInteractionController
|
||||
implements GestureHandlerInteractionController {
|
||||
|
||||
@Override
|
||||
public boolean shouldWaitForHandlerFailure(GestureHandler handler,
|
||||
GestureHandler otherHandler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRequireHandlerToWaitForFailure(GestureHandler handler,
|
||||
GestureHandler otherHandler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRecognizeSimultaneously(GestureHandler handler,
|
||||
GestureHandler otherHandler) {
|
||||
return false;
|
||||
}
|
||||
}
|
110
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/FlingGestureHandler.java
generated
vendored
Normal file
110
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/FlingGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class FlingGestureHandler extends GestureHandler<FlingGestureHandler> {
|
||||
private static final long DEFAULT_MAX_DURATION_MS = 800;
|
||||
private static final long DEFAULT_MIN_ACCEPTABLE_DELTA = 160;
|
||||
private static final int DEFAULT_DIRECTION = DIRECTION_RIGHT;
|
||||
private static final int DEFAULT_NUMBER_OF_TOUCHES_REQUIRED = 1;
|
||||
|
||||
private long mMaxDurationMs = DEFAULT_MAX_DURATION_MS;
|
||||
private long mMinAcceptableDelta = DEFAULT_MIN_ACCEPTABLE_DELTA;
|
||||
private int mDirection = DEFAULT_DIRECTION;
|
||||
private int mNumberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED;
|
||||
private float mStartX, mStartY;
|
||||
|
||||
private Handler mHandler;
|
||||
private int mMaxNumberOfPointersSimultaneously;
|
||||
|
||||
private final Runnable mFailDelayed = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fail();
|
||||
}
|
||||
};
|
||||
|
||||
public void setNumberOfPointersRequired(int numberOfPointersRequired) {
|
||||
mNumberOfPointersRequired = numberOfPointersRequired;
|
||||
}
|
||||
|
||||
public void setDirection(int direction) {
|
||||
mDirection = direction;
|
||||
}
|
||||
|
||||
private void startFling(MotionEvent event) {
|
||||
mStartX = event.getRawX();
|
||||
mStartY = event.getRawY();
|
||||
begin();
|
||||
mMaxNumberOfPointersSimultaneously = 1;
|
||||
if (mHandler == null) {
|
||||
mHandler = new Handler();
|
||||
} else {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
mHandler.postDelayed(mFailDelayed, mMaxDurationMs);
|
||||
}
|
||||
|
||||
private boolean tryEndFling(MotionEvent event) {
|
||||
if (mMaxNumberOfPointersSimultaneously == mNumberOfPointersRequired &&
|
||||
(((mDirection & DIRECTION_RIGHT) != 0 &&
|
||||
event.getRawX() - mStartX > mMinAcceptableDelta) ||
|
||||
((mDirection & DIRECTION_LEFT) !=0 &&
|
||||
mStartX - event.getRawX() > mMinAcceptableDelta) ||
|
||||
((mDirection & DIRECTION_UP) !=0 &&
|
||||
mStartY - event.getRawY() > mMinAcceptableDelta) ||
|
||||
((mDirection & DIRECTION_DOWN) !=0 &&
|
||||
event.getRawY() - mStartY > mMinAcceptableDelta))) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
activate();
|
||||
end();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void endFling(MotionEvent event) {
|
||||
if (!tryEndFling(event)) {
|
||||
fail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
int state = getState();
|
||||
|
||||
if (state == STATE_UNDETERMINED) {
|
||||
startFling(event);
|
||||
}
|
||||
|
||||
|
||||
if (state == STATE_BEGAN) {
|
||||
tryEndFling(event);
|
||||
if (event.getPointerCount() > mMaxNumberOfPointersSimultaneously) {
|
||||
mMaxNumberOfPointersSimultaneously = event.getPointerCount();
|
||||
}
|
||||
|
||||
int action = event.getActionMasked();
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
endFling(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancel() {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
}
|
531
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandler.java
generated
vendored
Normal file
531
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,531 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GestureHandler<T extends GestureHandler> {
|
||||
|
||||
public static final int STATE_UNDETERMINED = 0;
|
||||
public static final int STATE_FAILED = 1;
|
||||
public static final int STATE_BEGAN = 2;
|
||||
public static final int STATE_CANCELLED = 3;
|
||||
public static final int STATE_ACTIVE = 4;
|
||||
public static final int STATE_END = 5;
|
||||
|
||||
public static final float HIT_SLOP_NONE = Float.NaN;
|
||||
|
||||
private static final int HIT_SLOP_LEFT_IDX = 0;
|
||||
private static final int HIT_SLOP_TOP_IDX = 1;
|
||||
private static final int HIT_SLOP_RIGHT_IDX = 2;
|
||||
private static final int HIT_SLOP_BOTTOM_IDX = 3;
|
||||
private static final int HIT_SLOP_WIDTH_IDX = 4;
|
||||
private static final int HIT_SLOP_HEIGHT_IDX = 5;
|
||||
|
||||
public static final int DIRECTION_RIGHT = 1;
|
||||
public static final int DIRECTION_LEFT = 2;
|
||||
public static final int DIRECTION_UP = 4;
|
||||
public static final int DIRECTION_DOWN = 8;
|
||||
|
||||
private static int MAX_POINTERS_COUNT = 12;
|
||||
private static MotionEvent.PointerProperties[] sPointerProps;
|
||||
private static MotionEvent.PointerCoords[] sPointerCoords;
|
||||
|
||||
private static void initPointerProps(int size) {
|
||||
if (sPointerProps == null) {
|
||||
sPointerProps = new MotionEvent.PointerProperties[MAX_POINTERS_COUNT];
|
||||
sPointerCoords = new MotionEvent.PointerCoords[MAX_POINTERS_COUNT];
|
||||
}
|
||||
for (; size > 0 && sPointerProps[size - 1] == null; size--) {
|
||||
sPointerProps[size - 1] = new MotionEvent.PointerProperties();
|
||||
sPointerCoords[size - 1] = new MotionEvent.PointerCoords();
|
||||
}
|
||||
}
|
||||
|
||||
private final int[] mTrackedPointerIDs = new int[MAX_POINTERS_COUNT];
|
||||
private int mTrackedPointersCount = 0;
|
||||
|
||||
private int mTag;
|
||||
private View mView;
|
||||
private int mState = STATE_UNDETERMINED;
|
||||
private float mX, mY;
|
||||
private boolean mWithinBounds;
|
||||
private boolean mEnabled = true;
|
||||
private float mHitSlop[];
|
||||
|
||||
private static short sNextEventCoalescingKey = 0;
|
||||
private short mEventCoalescingKey;
|
||||
|
||||
private float mLastX, mLastY;
|
||||
private float mLastEventOffsetX, mLastEventOffsetY;
|
||||
|
||||
private boolean mShouldCancelWhenOutside;
|
||||
private int mNumberOfPointers = 0;
|
||||
|
||||
private GestureHandlerOrchestrator mOrchestrator;
|
||||
private OnTouchEventListener<T> mListener;
|
||||
private GestureHandlerInteractionController mInteractionController;
|
||||
/*package*/ int mActivationIndex; // set and accessed only by the orchestrator
|
||||
/*package*/ boolean mIsActive; // set and accessed only by the orchestrator
|
||||
/*package*/ boolean mIsAwaiting; // set and accessed only by the orchestrator
|
||||
|
||||
private static boolean hitSlopSet(float value) {
|
||||
return !Float.isNaN(value);
|
||||
}
|
||||
|
||||
/*package*/ void dispatchStateChange(int newState, int prevState) {
|
||||
if (mListener != null) {
|
||||
mListener.onStateChange((T) this, newState, prevState);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void dispatchTouchEvent(MotionEvent event) {
|
||||
if (mListener != null) {
|
||||
mListener.onTouchEvent((T) this, event);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasCommonPointers(GestureHandler other) {
|
||||
for (int i = 0; i < mTrackedPointerIDs.length; i++) {
|
||||
if (mTrackedPointerIDs[i] != -1 && other.mTrackedPointerIDs[i] != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public T setShouldCancelWhenOutside(boolean shouldCancelWhenOutside) {
|
||||
mShouldCancelWhenOutside = shouldCancelWhenOutside;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T setEnabled(boolean enabled) {
|
||||
if (mView != null) {
|
||||
// If view is set then handler is in "active" state. In that case we want to "cancel" handler
|
||||
// when it changes enabled state so that it gets cleared from the orchestrator
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
mEnabled = enabled;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
public T setHitSlop(float leftPad, float topPad, float rightPad, float bottomPad, float width, float height) {
|
||||
if (mHitSlop == null) {
|
||||
mHitSlop = new float[6];
|
||||
}
|
||||
mHitSlop[HIT_SLOP_LEFT_IDX] = leftPad;
|
||||
mHitSlop[HIT_SLOP_TOP_IDX] = topPad;
|
||||
mHitSlop[HIT_SLOP_RIGHT_IDX] = rightPad;
|
||||
mHitSlop[HIT_SLOP_BOTTOM_IDX] = bottomPad;
|
||||
mHitSlop[HIT_SLOP_WIDTH_IDX] = width;
|
||||
mHitSlop[HIT_SLOP_HEIGHT_IDX] = height;
|
||||
if (hitSlopSet(width) && hitSlopSet(leftPad) && hitSlopSet(rightPad)) {
|
||||
throw new IllegalArgumentException("Cannot have all of left, right and width defined");
|
||||
}
|
||||
if (hitSlopSet(width) && !hitSlopSet(leftPad) && !hitSlopSet(rightPad)) {
|
||||
throw new IllegalArgumentException("When width is set one of left or right pads need to be defined");
|
||||
}
|
||||
if (hitSlopSet(height) && hitSlopSet(bottomPad) && hitSlopSet(topPad)) {
|
||||
throw new IllegalArgumentException("Cannot have all of top, bottom and height defined");
|
||||
}
|
||||
if (hitSlopSet(height) && !hitSlopSet(bottomPad) && !hitSlopSet(topPad)) {
|
||||
throw new IllegalArgumentException("When height is set one of top or bottom pads need to be defined");
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T setHitSlop(float padding) {
|
||||
return setHitSlop(padding, padding, padding, padding, HIT_SLOP_NONE, HIT_SLOP_NONE);
|
||||
}
|
||||
|
||||
public T setInteractionController(GestureHandlerInteractionController controller) {
|
||||
mInteractionController = controller;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public void setTag(int tag) {
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
public int getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return mX;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return mY;
|
||||
}
|
||||
|
||||
public int getNumberOfPointers() {
|
||||
return mNumberOfPointers;
|
||||
}
|
||||
|
||||
public boolean isWithinBounds() {
|
||||
return mWithinBounds;
|
||||
}
|
||||
|
||||
public short getEventCoalescingKey() {
|
||||
return mEventCoalescingKey;
|
||||
}
|
||||
|
||||
public final void prepare(View view, GestureHandlerOrchestrator orchestrator) {
|
||||
if (mView != null || mOrchestrator != null) {
|
||||
throw new IllegalStateException("Already prepared or hasn't been reset");
|
||||
}
|
||||
Arrays.fill(mTrackedPointerIDs, -1);
|
||||
mTrackedPointersCount = 0;
|
||||
mState = STATE_UNDETERMINED;
|
||||
|
||||
mView = view;
|
||||
mOrchestrator = orchestrator;
|
||||
}
|
||||
|
||||
private int findNextLocalPointerId() {
|
||||
int localPointerId = 0;
|
||||
for (; localPointerId < mTrackedPointersCount; localPointerId++) {
|
||||
int i = 0;
|
||||
for (; i < mTrackedPointerIDs.length; i++) {
|
||||
if (mTrackedPointerIDs[i] == localPointerId) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == mTrackedPointerIDs.length) {
|
||||
return localPointerId;
|
||||
}
|
||||
}
|
||||
return localPointerId;
|
||||
}
|
||||
|
||||
public void startTrackingPointer(int pointerId) {
|
||||
if (mTrackedPointerIDs[pointerId] == -1) {
|
||||
mTrackedPointerIDs[pointerId] = findNextLocalPointerId();
|
||||
mTrackedPointersCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopTrackingPointer(int pointerId) {
|
||||
if (mTrackedPointerIDs[pointerId] != -1) {
|
||||
mTrackedPointerIDs[pointerId] = -1;
|
||||
mTrackedPointersCount--;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needAdapt(MotionEvent event) {
|
||||
if (event.getPointerCount() != mTrackedPointersCount) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < mTrackedPointerIDs.length; i++) {
|
||||
if (mTrackedPointerIDs[i] != -1 && mTrackedPointerIDs[i] != i) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private MotionEvent adaptEvent(MotionEvent event) {
|
||||
if (!needAdapt(event)) {
|
||||
return event;
|
||||
}
|
||||
int action = event.getActionMasked();
|
||||
int actionIndex = -1;
|
||||
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
actionIndex = event.getActionIndex();
|
||||
int actionPointer = event.getPointerId(actionIndex);
|
||||
if (mTrackedPointerIDs[actionPointer] != -1) {
|
||||
action = mTrackedPointersCount == 1 ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_POINTER_DOWN;
|
||||
} else {
|
||||
action = MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
|
||||
actionIndex = event.getActionIndex();
|
||||
int actionPointer = event.getPointerId(actionIndex);
|
||||
if (mTrackedPointerIDs[actionPointer] != -1) {
|
||||
action = mTrackedPointersCount == 1 ? MotionEvent.ACTION_UP : MotionEvent.ACTION_POINTER_UP;
|
||||
} else {
|
||||
action = MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
}
|
||||
initPointerProps(mTrackedPointersCount);
|
||||
int count = 0;
|
||||
float oldX = event.getX();
|
||||
float oldY = event.getY();
|
||||
event.setLocation(event.getRawX(), event.getRawY());
|
||||
for (int index = 0, size = event.getPointerCount(); index < size; index++) {
|
||||
int origPointerId = event.getPointerId(index);
|
||||
if (mTrackedPointerIDs[origPointerId] != -1) {
|
||||
event.getPointerProperties(index, sPointerProps[count]);
|
||||
sPointerProps[count].id = mTrackedPointerIDs[origPointerId];
|
||||
event.getPointerCoords(index, sPointerCoords[count]);
|
||||
if (index == actionIndex) {
|
||||
action = action | (count << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
MotionEvent result = MotionEvent.obtain(
|
||||
event.getDownTime(),
|
||||
event.getEventTime(),
|
||||
action,
|
||||
count,
|
||||
sPointerProps, /* props are copied and hence it is safe to use static array here */
|
||||
sPointerCoords, /* same applies to coords */
|
||||
event.getMetaState(),
|
||||
event.getButtonState(),
|
||||
event.getXPrecision(),
|
||||
event.getYPrecision(),
|
||||
event.getDeviceId(),
|
||||
event.getEdgeFlags(),
|
||||
event.getSource(),
|
||||
event.getFlags());
|
||||
event.setLocation(oldX, oldY);
|
||||
result.setLocation(oldX, oldY);
|
||||
return result;
|
||||
}
|
||||
|
||||
public final void handle(MotionEvent origEvent) {
|
||||
if (!mEnabled || mState == STATE_CANCELLED || mState == STATE_FAILED
|
||||
|| mState == STATE_END || mTrackedPointersCount < 1) {
|
||||
return;
|
||||
}
|
||||
MotionEvent event = adaptEvent(origEvent);
|
||||
mX = event.getX();
|
||||
mY = event.getY();
|
||||
mNumberOfPointers = event.getPointerCount();
|
||||
|
||||
mWithinBounds = isWithinBounds(mView, mX, mY);
|
||||
if (mShouldCancelWhenOutside && !mWithinBounds) {
|
||||
if (mState == STATE_ACTIVE) {
|
||||
cancel();
|
||||
} else if (mState == STATE_BEGAN) {
|
||||
fail();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mLastX = GestureUtils.getLastPointerX(event, true);
|
||||
mLastY = GestureUtils.getLastPointerY(event, true);
|
||||
mLastEventOffsetX = event.getRawX() - event.getX();
|
||||
mLastEventOffsetY = event.getRawY() - event.getY();
|
||||
|
||||
onHandle(event);
|
||||
if (event != origEvent) {
|
||||
event.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToState(int newState) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
if (mState == newState) {
|
||||
return;
|
||||
}
|
||||
int oldState = mState;
|
||||
mState = newState;
|
||||
|
||||
if (mState == STATE_ACTIVE) {
|
||||
// Generate a unique coalescing-key each time the gesture-handler becomes active. All events will have
|
||||
// the same coalescing-key allowing EventDispatcher to coalesce RNGestureHandlerEvents when events are
|
||||
// generated faster than they can be treated by JS thread
|
||||
mEventCoalescingKey = sNextEventCoalescingKey++;
|
||||
}
|
||||
|
||||
mOrchestrator.onHandlerStateChange(this, newState, oldState);
|
||||
|
||||
onStateChange(newState, oldState);
|
||||
}
|
||||
|
||||
public boolean wantEvents() {
|
||||
return mEnabled && mState != STATE_FAILED && mState != STATE_CANCELLED
|
||||
&& mState != STATE_END && mTrackedPointersCount > 0;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
public boolean shouldRequireToWaitForFailure(GestureHandler handler) {
|
||||
if (handler != this && mInteractionController != null) {
|
||||
return mInteractionController.shouldRequireHandlerToWaitForFailure(this, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldWaitForHandlerFailure(GestureHandler handler) {
|
||||
if (handler != this && mInteractionController != null) {
|
||||
return mInteractionController.shouldWaitForHandlerFailure(this, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldRecognizeSimultaneously(GestureHandler handler) {
|
||||
if (handler == this) {
|
||||
return true;
|
||||
}
|
||||
if (mInteractionController != null) {
|
||||
return mInteractionController.shouldRecognizeSimultaneously(this, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldBeCancelledBy(GestureHandler handler) {
|
||||
if (handler == this) {
|
||||
return false;
|
||||
}
|
||||
if (mInteractionController != null) {
|
||||
return mInteractionController.shouldHandlerBeCancelledBy(this, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isWithinBounds(View view, float posX, float posY) {
|
||||
float left = 0;
|
||||
float top = 0;
|
||||
float right = view.getWidth();
|
||||
float bottom = view.getHeight();
|
||||
if (mHitSlop != null) {
|
||||
float padLeft = mHitSlop[HIT_SLOP_LEFT_IDX];
|
||||
float padTop = mHitSlop[HIT_SLOP_TOP_IDX];
|
||||
float padRight = mHitSlop[HIT_SLOP_RIGHT_IDX];
|
||||
float padBottom = mHitSlop[HIT_SLOP_BOTTOM_IDX];
|
||||
if (hitSlopSet(padLeft)) {
|
||||
left -= padLeft;
|
||||
}
|
||||
if (hitSlopSet(padTop)) {
|
||||
top -= padBottom;
|
||||
}
|
||||
if (hitSlopSet(padRight)) {
|
||||
right += padRight;
|
||||
}
|
||||
if (hitSlopSet(padBottom)) {
|
||||
bottom += padBottom;
|
||||
}
|
||||
|
||||
float width = mHitSlop[HIT_SLOP_WIDTH_IDX];
|
||||
float height= mHitSlop[HIT_SLOP_HEIGHT_IDX];
|
||||
if (hitSlopSet(width)) {
|
||||
if (!hitSlopSet(padLeft)) {
|
||||
left = right - width;
|
||||
} else if (!hitSlopSet(padRight)) {
|
||||
right = left + width;
|
||||
}
|
||||
}
|
||||
if (hitSlopSet(height)) {
|
||||
if (!hitSlopSet(top)) {
|
||||
top = bottom - height;
|
||||
} else if (!hitSlopSet(bottom)) {
|
||||
bottom = top + height;
|
||||
}
|
||||
}
|
||||
}
|
||||
return posX >= left && posX <= right && posY >= top && posY <= bottom;
|
||||
}
|
||||
|
||||
public final void cancel() {
|
||||
if (mState == STATE_ACTIVE || mState == STATE_UNDETERMINED || mState == STATE_BEGAN) {
|
||||
onCancel();
|
||||
moveToState(STATE_CANCELLED);
|
||||
}
|
||||
}
|
||||
|
||||
public final void fail() {
|
||||
if (mState == STATE_ACTIVE || mState == STATE_UNDETERMINED || mState == STATE_BEGAN) {
|
||||
moveToState(STATE_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
public final void activate() {
|
||||
if (mState == STATE_UNDETERMINED || mState == STATE_BEGAN) {
|
||||
moveToState(STATE_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
public final void begin() {
|
||||
if (mState == STATE_UNDETERMINED) {
|
||||
moveToState(STATE_BEGAN);
|
||||
}
|
||||
}
|
||||
|
||||
public final void end() {
|
||||
if (mState == STATE_BEGAN || mState == STATE_ACTIVE) {
|
||||
moveToState(STATE_END);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onHandle(MotionEvent event) {
|
||||
moveToState(STATE_FAILED);
|
||||
}
|
||||
|
||||
protected void onStateChange(int newState, int previousState) {
|
||||
}
|
||||
|
||||
protected void onReset() {
|
||||
}
|
||||
|
||||
protected void onCancel() {
|
||||
}
|
||||
|
||||
public final void reset() {
|
||||
mView = null;
|
||||
mOrchestrator = null;
|
||||
Arrays.fill(mTrackedPointerIDs, -1);
|
||||
mTrackedPointersCount = 0;
|
||||
onReset();
|
||||
}
|
||||
|
||||
public static String stateToString(int state) {
|
||||
switch (state) {
|
||||
case STATE_UNDETERMINED: return "UNDETERMINED";
|
||||
case STATE_ACTIVE: return "ACTIVE";
|
||||
case STATE_FAILED: return "FAILED";
|
||||
case STATE_BEGAN: return "BEGIN";
|
||||
case STATE_CANCELLED: return "CANCELLED";
|
||||
case STATE_END: return "END";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public GestureHandler setOnTouchEventListener(OnTouchEventListener<T> listener) {
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String viewString = mView == null ? null : mView.getClass().getSimpleName();
|
||||
return this.getClass().getSimpleName() + "@[" + mTag + "]:" + viewString;
|
||||
}
|
||||
|
||||
public float getLastAbsolutePositionX() {
|
||||
return mLastX;
|
||||
}
|
||||
|
||||
public float getLastAbsolutePositionY() {
|
||||
return mLastY;
|
||||
}
|
||||
|
||||
public float getLastRelativePositionX() {
|
||||
return mLastX - mLastEventOffsetX;
|
||||
}
|
||||
|
||||
public float getLastRelativePositionY() {
|
||||
return mLastY - mLastEventOffsetY;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
public interface GestureHandlerInteractionController {
|
||||
boolean shouldWaitForHandlerFailure(GestureHandler handler, GestureHandler otherHandler);
|
||||
boolean shouldRequireHandlerToWaitForFailure(GestureHandler handler, GestureHandler otherHandler);
|
||||
boolean shouldRecognizeSimultaneously(GestureHandler handler, GestureHandler otherHandler);
|
||||
boolean shouldHandlerBeCancelledBy(GestureHandler handler, GestureHandler otherHandler);
|
||||
}
|
543
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java
generated
vendored
Normal file
543
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java
generated
vendored
Normal file
@ -0,0 +1,543 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class GestureHandlerOrchestrator {
|
||||
|
||||
// The limit doesn't necessarily need to exists, it was just simpler to implement it that way
|
||||
// it is also more allocation-wise efficient to have a fixed limit
|
||||
private static final int SIMULTANEOUS_GESTURE_HANDLER_LIMIT = 20;
|
||||
// Be default fully transparent views can receive touch
|
||||
private static final float DEFAULT_MIN_ALPHA_FOR_TRAVERSAL = 0f;
|
||||
|
||||
private static final PointF sTempPoint = new PointF();
|
||||
private static final float[] sMatrixTransformCoords = new float[2];
|
||||
private static final Matrix sInverseMatrix = new Matrix();
|
||||
private static final float[] sTempCoords = new float[2];
|
||||
|
||||
private static final Comparator<GestureHandler> sHandlersComparator =
|
||||
new Comparator<GestureHandler>() {
|
||||
@Override
|
||||
public int compare(GestureHandler a, GestureHandler b) {
|
||||
if (a.mIsActive && b.mIsActive || a.mIsAwaiting && b.mIsAwaiting) {
|
||||
// both A and B are either active or awaiting activation, in which case we prefer one that
|
||||
// has activated (or turned into "awaiting" state) earlier
|
||||
return Integer.signum(b.mActivationIndex - a.mActivationIndex);
|
||||
} else if (a.mIsActive) {
|
||||
return -1; // only A is active
|
||||
} else if (b.mIsActive) {
|
||||
return 1; // only B is active
|
||||
} else if (a.mIsAwaiting) {
|
||||
return -1; // only A is awaiting, B is inactive
|
||||
} else if (b.mIsAwaiting) {
|
||||
return 1; // only B is awaiting, A is inactive
|
||||
}
|
||||
return 0; // both A and B are inactive, stable order matters
|
||||
}
|
||||
};
|
||||
|
||||
private final ViewGroup mWrapperView;
|
||||
private final GestureHandlerRegistry mHandlerRegistry;
|
||||
private final ViewConfigurationHelper mViewConfigHelper;
|
||||
|
||||
private final GestureHandler[] mGestureHandlers
|
||||
= new GestureHandler[SIMULTANEOUS_GESTURE_HANDLER_LIMIT];
|
||||
private final GestureHandler[] mAwaitingHandlers
|
||||
= new GestureHandler[SIMULTANEOUS_GESTURE_HANDLER_LIMIT];
|
||||
private final GestureHandler[] mPreparedHandlers
|
||||
= new GestureHandler[SIMULTANEOUS_GESTURE_HANDLER_LIMIT];
|
||||
private final GestureHandler[] mHandlersToCancel
|
||||
= new GestureHandler[SIMULTANEOUS_GESTURE_HANDLER_LIMIT];
|
||||
private int mGestureHandlersCount = 0;
|
||||
private int mAwaitingHandlersCount = 0;
|
||||
|
||||
private boolean mIsHandlingTouch = false;
|
||||
private int mHandlingChangeSemaphore = 0;
|
||||
private boolean mFinishedHandlersCleanupScheduled = false;
|
||||
private int mActivationIndex = 0;
|
||||
|
||||
private float mMinAlphaForTraversal = DEFAULT_MIN_ALPHA_FOR_TRAVERSAL;
|
||||
|
||||
public GestureHandlerOrchestrator(
|
||||
ViewGroup wrapperView,
|
||||
GestureHandlerRegistry registry,
|
||||
ViewConfigurationHelper viewConfigurationHelper) {
|
||||
mWrapperView = wrapperView;
|
||||
mHandlerRegistry = registry;
|
||||
mViewConfigHelper = viewConfigurationHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum alpha (value from 0 to 1) that should be set to a view so that it can be treated as a
|
||||
* gesture target. E.g. if set to 0.1 then views that less than 10% opaque will be ignored when
|
||||
* traversing view hierarchy and looking for gesture handlers.
|
||||
*/
|
||||
public void setMinimumAlphaForTraversal(float alpha) {
|
||||
mMinAlphaForTraversal = alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called from the view wrapper
|
||||
*/
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
mIsHandlingTouch = true;
|
||||
int action = event.getActionMasked();
|
||||
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
extractGestureHandlers(event);
|
||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||
cancelAll();
|
||||
}
|
||||
deliverEventToGestureHandlers(event);
|
||||
mIsHandlingTouch = false;
|
||||
if (mFinishedHandlersCleanupScheduled && mHandlingChangeSemaphore == 0) {
|
||||
cleanupFinishedHandlers();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void scheduleFinishedHandlersCleanup() {
|
||||
if (mIsHandlingTouch || mHandlingChangeSemaphore != 0) {
|
||||
mFinishedHandlersCleanupScheduled = true;
|
||||
} else {
|
||||
cleanupFinishedHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupFinishedHandlers() {
|
||||
boolean shouldCleanEmptyCells = false;
|
||||
for (int i = mGestureHandlersCount - 1; i >= 0; i--) {
|
||||
GestureHandler handler = mGestureHandlers[i];
|
||||
if (isFinished(handler.getState()) && !handler.mIsAwaiting) {
|
||||
mGestureHandlers[i] = null;
|
||||
shouldCleanEmptyCells = true;
|
||||
handler.reset();
|
||||
handler.mIsActive = false;
|
||||
handler.mIsAwaiting = false;
|
||||
handler.mActivationIndex = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
if (shouldCleanEmptyCells) {
|
||||
int out = 0;
|
||||
for (int i = 0; i < mGestureHandlersCount; i++) {
|
||||
if (mGestureHandlers[i] != null) {
|
||||
mGestureHandlers[out++] = mGestureHandlers[i];
|
||||
}
|
||||
}
|
||||
mGestureHandlersCount = out;
|
||||
}
|
||||
mFinishedHandlersCleanupScheduled = false;
|
||||
}
|
||||
|
||||
private boolean hasOtherHandlerToWaitFor(GestureHandler handler) {
|
||||
for (int i = 0; i < mGestureHandlersCount; i++) {
|
||||
GestureHandler otherHandler = mGestureHandlers[i];
|
||||
if (!isFinished(otherHandler.getState())
|
||||
&& shouldHandlerWaitForOther(handler, otherHandler)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void tryActivate(GestureHandler handler) {
|
||||
// see if there is anyone else who we need to wait for
|
||||
if (hasOtherHandlerToWaitFor(handler)) {
|
||||
addAwaitingHandler(handler);
|
||||
} else {
|
||||
// we can activate handler right away
|
||||
makeActive(handler);
|
||||
handler.mIsAwaiting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupAwaitingHandlers() {
|
||||
int out = 0;
|
||||
for (int i = 0; i < mAwaitingHandlersCount; i++) {
|
||||
if (mAwaitingHandlers[i].mIsAwaiting) {
|
||||
mAwaitingHandlers[out++] = mAwaitingHandlers[i];
|
||||
}
|
||||
}
|
||||
mAwaitingHandlersCount = out;
|
||||
}
|
||||
|
||||
/*package*/ void onHandlerStateChange(GestureHandler handler, int newState, int prevState) {
|
||||
mHandlingChangeSemaphore += 1;
|
||||
if (isFinished(newState)) {
|
||||
// if there were handlers awaiting completion of this handler, we can trigger active state
|
||||
for (int i = 0; i < mAwaitingHandlersCount; i++) {
|
||||
GestureHandler otherHandler = mAwaitingHandlers[i];
|
||||
if (shouldHandlerWaitForOther(otherHandler, handler)) {
|
||||
if (newState == GestureHandler.STATE_END) {
|
||||
// gesture has ended, we need to kill the awaiting handler
|
||||
otherHandler.cancel();
|
||||
otherHandler.mIsAwaiting = false;
|
||||
} else {
|
||||
// gesture has failed recognition, we may try activating
|
||||
tryActivate(otherHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanupAwaitingHandlers();
|
||||
}
|
||||
if (newState == GestureHandler.STATE_ACTIVE) {
|
||||
tryActivate(handler);
|
||||
} else if (prevState == GestureHandler.STATE_ACTIVE || prevState == GestureHandler.STATE_END) {
|
||||
if (handler.mIsActive) {
|
||||
handler.dispatchStateChange(newState, prevState);
|
||||
}
|
||||
} else {
|
||||
handler.dispatchStateChange(newState, prevState);
|
||||
}
|
||||
mHandlingChangeSemaphore -= 1;
|
||||
scheduleFinishedHandlersCleanup();
|
||||
}
|
||||
|
||||
private void makeActive(GestureHandler handler) {
|
||||
int currentState = handler.getState();
|
||||
|
||||
handler.mIsAwaiting = false;
|
||||
handler.mIsActive = true;
|
||||
handler.mActivationIndex = mActivationIndex++;
|
||||
|
||||
int toCancelCount = 0;
|
||||
// Cancel all handlers that are required to be cancel upon current handler's activation
|
||||
for (int i = 0; i < mGestureHandlersCount; i++) {
|
||||
GestureHandler otherHandler = mGestureHandlers[i];
|
||||
if (shouldHandlerBeCancelledBy(otherHandler, handler)) {
|
||||
mHandlersToCancel[toCancelCount++] = otherHandler;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = toCancelCount - 1; i >= 0; i--) {
|
||||
mHandlersToCancel[i].cancel();
|
||||
}
|
||||
|
||||
// Clear all awaiting handlers waiting for the current handler to fail
|
||||
for (int i = mAwaitingHandlersCount - 1; i >= 0; i--) {
|
||||
GestureHandler otherHandler = mAwaitingHandlers[i];
|
||||
if (shouldHandlerBeCancelledBy(otherHandler, handler)) {
|
||||
otherHandler.cancel();
|
||||
otherHandler.mIsAwaiting = false;
|
||||
}
|
||||
}
|
||||
cleanupAwaitingHandlers();
|
||||
|
||||
// Dispatch state change event if handler is no longer in the active state we should also
|
||||
// trigger END state change and UNDETERMINED state change if necessary
|
||||
handler.dispatchStateChange(GestureHandler.STATE_ACTIVE, GestureHandler.STATE_BEGAN);
|
||||
if (currentState != GestureHandler.STATE_ACTIVE) {
|
||||
handler.dispatchStateChange(GestureHandler.STATE_END, GestureHandler.STATE_ACTIVE);
|
||||
if (currentState != GestureHandler.STATE_END) {
|
||||
handler.dispatchStateChange(GestureHandler.STATE_UNDETERMINED, GestureHandler.STATE_END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deliverEventToGestureHandlers(MotionEvent event) {
|
||||
// Copy handlers to "prepared handlers" array, because the list of active handlers can change
|
||||
// as a result of state updates
|
||||
int handlersCount = mGestureHandlersCount;
|
||||
System.arraycopy(mGestureHandlers, 0, mPreparedHandlers, 0, handlersCount);
|
||||
// We want to deliver events to active handlers first in order of their activation (handlers
|
||||
// that activated first will first get event delivered). Otherwise we deliver events in the
|
||||
// order in which handlers has been added ("most direct" children goes first). Therefore we rely
|
||||
// on Arrays.sort providing a stable sort (as children are registered in order in which they
|
||||
// should be tested)
|
||||
Arrays.sort(mPreparedHandlers, 0, handlersCount, sHandlersComparator);
|
||||
for (int i = 0; i < handlersCount; i++) {
|
||||
deliverEventToGestureHandler(mPreparedHandlers[i], event);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAll() {
|
||||
for (int i = mAwaitingHandlersCount - 1; i >= 0; i--) {
|
||||
mAwaitingHandlers[i].cancel();
|
||||
}
|
||||
// Copy handlers to "prepared handlers" array, because the list of active handlers can change
|
||||
// as a result of state updates
|
||||
int handlersCount = mGestureHandlersCount;
|
||||
for (int i = 0; i < handlersCount; i++) {
|
||||
mPreparedHandlers[i] = mGestureHandlers[i];
|
||||
}
|
||||
for (int i = handlersCount - 1; i >= 0; i--) {
|
||||
mPreparedHandlers[i].cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void deliverEventToGestureHandler(GestureHandler handler, MotionEvent event) {
|
||||
if (!isViewAttachedUnderWrapper(handler.getView())) {
|
||||
handler.cancel();
|
||||
return;
|
||||
}
|
||||
if (!handler.wantEvents()) {
|
||||
return;
|
||||
}
|
||||
int action = event.getActionMasked();
|
||||
if (handler.mIsAwaiting && action == MotionEvent.ACTION_MOVE) {
|
||||
return;
|
||||
}
|
||||
float[] coords = sTempCoords;
|
||||
extractCoordsForView(handler.getView(), event, coords);
|
||||
float oldX = event.getX();
|
||||
float oldY = event.getY();
|
||||
// TODO: we may conside scaling events if necessary using MotionEvent.transform
|
||||
// for now the events are only offset to the top left corner of the view but if
|
||||
// view or any ot the parents is scaled the other pointers position will not reflect
|
||||
// their actual place in the view. On the other hand not scaling seems like a better
|
||||
// approach when we want to use pointer coordinates to calculate velocity or distance
|
||||
// for pinch so I don't know yet if we should transform or not...
|
||||
event.setLocation(coords[0], coords[1]);
|
||||
handler.handle(event);
|
||||
if (handler.mIsActive) {
|
||||
handler.dispatchTouchEvent(event);
|
||||
}
|
||||
event.setLocation(oldX, oldY);
|
||||
// if event was of type UP or POINTER_UP we request handler to stop tracking now that
|
||||
// the event has been dispatched
|
||||
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
|
||||
int pointerId = event.getPointerId(event.getActionIndex());
|
||||
handler.stopTrackingPointer(pointerId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* isViewAttachedUnderWrapper checks whether all of parents for view related to handler
|
||||
* view are attached. Since there might be an issue rarely observed when view
|
||||
* has been detached and handler's state hasn't been change to canceled, failed or
|
||||
* ended yet. Probably it's a result of some race condition and stopping delivering
|
||||
* for this handler and changing its state to failed of end appear to be good enough solution.
|
||||
*/
|
||||
private boolean isViewAttachedUnderWrapper(@Nullable View view) {
|
||||
if (view == null) {
|
||||
return false;
|
||||
}
|
||||
if (view == mWrapperView) {
|
||||
return true;
|
||||
}
|
||||
@Nullable ViewParent parent = view.getParent();
|
||||
while (parent != null && parent != mWrapperView) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return parent == mWrapperView;
|
||||
}
|
||||
|
||||
private void extractCoordsForView(View view, MotionEvent event, float[] outputCoords) {
|
||||
if (view == mWrapperView) {
|
||||
outputCoords[0] = event.getX();
|
||||
outputCoords[1] = event.getY();
|
||||
return;
|
||||
}
|
||||
if (view == null || !(view.getParent() instanceof ViewGroup)) {
|
||||
throw new IllegalArgumentException("Parent is null? View is no longer in the tree");
|
||||
}
|
||||
ViewGroup parent = (ViewGroup) view.getParent();
|
||||
extractCoordsForView(parent, event, outputCoords);
|
||||
PointF childPoint = sTempPoint;
|
||||
transformTouchPointToViewCoords(outputCoords[0], outputCoords[1], parent, view, childPoint);
|
||||
outputCoords[0] = childPoint.x;
|
||||
outputCoords[1] = childPoint.y;
|
||||
}
|
||||
|
||||
private void addAwaitingHandler(GestureHandler handler) {
|
||||
for (int i = 0; i < mAwaitingHandlersCount; i++) {
|
||||
if (mAwaitingHandlers[i] == handler) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mAwaitingHandlersCount >= mAwaitingHandlers.length) {
|
||||
throw new IllegalStateException("Too many recognizers");
|
||||
}
|
||||
mAwaitingHandlers[mAwaitingHandlersCount++] = handler;
|
||||
handler.mIsAwaiting = true;
|
||||
handler.mActivationIndex = mActivationIndex++;
|
||||
}
|
||||
|
||||
private void recordHandlerIfNotPresent(GestureHandler handler, View view) {
|
||||
for (int i = 0; i < mGestureHandlersCount; i++) {
|
||||
if (mGestureHandlers[i] == handler) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mGestureHandlersCount >= mGestureHandlers.length) {
|
||||
throw new IllegalStateException("Too many recognizers");
|
||||
}
|
||||
mGestureHandlers[mGestureHandlersCount++] = handler;
|
||||
handler.mIsActive = false;
|
||||
handler.mIsAwaiting = false;
|
||||
handler.mActivationIndex = Integer.MAX_VALUE;
|
||||
handler.prepare(view, this);
|
||||
}
|
||||
|
||||
private boolean recordViewHandlersForPointer(View view, float[] coords, int pointerId) {
|
||||
ArrayList<GestureHandler> handlers = mHandlerRegistry.getHandlersForView(view);
|
||||
boolean found = false;
|
||||
if (handlers != null) {
|
||||
for (int i = 0, size = handlers.size(); i < size; i++) {
|
||||
GestureHandler handler = handlers.get(i);
|
||||
if (handler.isEnabled() && handler.isWithinBounds(view, coords[0], coords[1])) {
|
||||
recordHandlerIfNotPresent(handler, view);
|
||||
handler.startTrackingPointer(pointerId);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private void extractGestureHandlers(MotionEvent event) {
|
||||
int actionIndex = event.getActionIndex();
|
||||
int pointerId = event.getPointerId(actionIndex);
|
||||
sTempCoords[0] = event.getX(actionIndex);
|
||||
sTempCoords[1] = event.getY(actionIndex);
|
||||
traverseWithPointerEvents(mWrapperView, sTempCoords, pointerId);
|
||||
extractGestureHandlers(mWrapperView, sTempCoords, pointerId);
|
||||
}
|
||||
|
||||
private boolean extractGestureHandlers(ViewGroup viewGroup, float[] coords, int pointerId) {
|
||||
int childrenCount = viewGroup.getChildCount();
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
View child = mViewConfigHelper.getChildInDrawingOrderAtIndex(viewGroup, i);
|
||||
if (canReceiveEvents(child)) {
|
||||
PointF childPoint = sTempPoint;
|
||||
transformTouchPointToViewCoords(coords[0], coords[1], viewGroup, child, childPoint);
|
||||
float restoreX = coords[0];
|
||||
float restoreY = coords[1];
|
||||
coords[0] = childPoint.x;
|
||||
coords[1] = childPoint.y;
|
||||
boolean found = false;
|
||||
if (!isClipping(child) || isTransformedTouchPointInView(coords[0], coords[1], child)) {
|
||||
// we only consider the view if touch is inside the view bounds or if the view's children
|
||||
// can render outside of the view bounds (overflow visible)
|
||||
found = traverseWithPointerEvents(child, coords, pointerId);
|
||||
}
|
||||
coords[0] = restoreX;
|
||||
coords[1] = restoreY;
|
||||
if (found) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean shouldHandlerlessViewBecomeTouchTarget(View view, float coords[]) {
|
||||
// The following code is to match the iOS behavior where transparent parts of the views can
|
||||
// pass touch events through them allowing sibling nodes to handle them.
|
||||
|
||||
// TODO: this is not an ideal solution as we only consider ViewGroups that has no background set
|
||||
// TODO: ideally we should determine the pixel color under the given coordinates and return
|
||||
// false if the color is transparent
|
||||
boolean isLeafOrTransparent = !(view instanceof ViewGroup) || view.getBackground() != null;
|
||||
return isLeafOrTransparent && isTransformedTouchPointInView(coords[0], coords[1], view);
|
||||
}
|
||||
|
||||
private boolean traverseWithPointerEvents(View view, float coords[], int pointerId) {
|
||||
PointerEventsConfig pointerEvents = mViewConfigHelper.getPointerEventsConfigForView(view);
|
||||
if (pointerEvents == PointerEventsConfig.NONE) {
|
||||
// This view and its children can't be the target
|
||||
return false;
|
||||
} else if (pointerEvents == PointerEventsConfig.BOX_ONLY) {
|
||||
// This view is the target, its children don't matter
|
||||
return recordViewHandlersForPointer(view, coords, pointerId)
|
||||
|| shouldHandlerlessViewBecomeTouchTarget(view, coords);
|
||||
} else if (pointerEvents == PointerEventsConfig.BOX_NONE) {
|
||||
// This view can't be the target, but its children might
|
||||
if (view instanceof ViewGroup) {
|
||||
return extractGestureHandlers((ViewGroup) view, coords, pointerId);
|
||||
}
|
||||
return false;
|
||||
} else if (pointerEvents == PointerEventsConfig.AUTO) {
|
||||
// Either this view or one of its children is the target
|
||||
boolean found = false;
|
||||
if (view instanceof ViewGroup) {
|
||||
found = extractGestureHandlers((ViewGroup) view, coords, pointerId);
|
||||
}
|
||||
return recordViewHandlersForPointer(view, coords, pointerId)
|
||||
|| found || shouldHandlerlessViewBecomeTouchTarget(view, coords);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown pointer event type: " + pointerEvents.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canReceiveEvents(View view) {
|
||||
return view.getVisibility() == View.VISIBLE && view.getAlpha() >= mMinAlphaForTraversal;
|
||||
}
|
||||
|
||||
private static void transformTouchPointToViewCoords(
|
||||
float x,
|
||||
float y,
|
||||
ViewGroup parent,
|
||||
View child,
|
||||
PointF outLocalPoint) {
|
||||
float localX = x + parent.getScrollX() - child.getLeft();
|
||||
float localY = y + parent.getScrollY() - child.getTop();
|
||||
Matrix matrix = child.getMatrix();
|
||||
if (!matrix.isIdentity()) {
|
||||
float[] localXY = sMatrixTransformCoords;
|
||||
localXY[0] = localX;
|
||||
localXY[1] = localY;
|
||||
Matrix inverseMatrix = sInverseMatrix;
|
||||
matrix.invert(inverseMatrix);
|
||||
inverseMatrix.mapPoints(localXY);
|
||||
localX = localXY[0];
|
||||
localY = localXY[1];
|
||||
}
|
||||
outLocalPoint.set(localX, localY);
|
||||
}
|
||||
|
||||
private boolean isClipping(View view) {
|
||||
// if view is not a view group it is clipping, otherwise we check for `getClipChildren` flag to
|
||||
// be turned on and also confirm with the ViewConfigHelper implementation
|
||||
return !(view instanceof ViewGroup) || mViewConfigHelper.isViewClippingChildren((ViewGroup) view);
|
||||
}
|
||||
|
||||
private static boolean isTransformedTouchPointInView(float x, float y, View child) {
|
||||
return x >= 0 && x <= child.getWidth() && y >= 0 && y < child.getHeight();
|
||||
}
|
||||
|
||||
private static boolean shouldHandlerWaitForOther(GestureHandler handler, GestureHandler other) {
|
||||
return handler != other && (handler.shouldWaitForHandlerFailure(other)
|
||||
|| other.shouldRequireToWaitForFailure(handler));
|
||||
}
|
||||
|
||||
private static boolean canRunSimultaneously(GestureHandler a, GestureHandler b) {
|
||||
return a == b || a.shouldRecognizeSimultaneously(b) || b.shouldRecognizeSimultaneously(a);
|
||||
}
|
||||
|
||||
private static boolean shouldHandlerBeCancelledBy(GestureHandler handler, GestureHandler other) {
|
||||
|
||||
if (!handler.hasCommonPointers(other)) {
|
||||
// if two handlers share no common pointer one can never trigger cancel for the other
|
||||
return false;
|
||||
}
|
||||
if (canRunSimultaneously(handler, other)) {
|
||||
// if handlers are allowed to run simultaneously, when first activates second can still remain
|
||||
// in began state
|
||||
return false;
|
||||
}
|
||||
if (handler != other &&
|
||||
(handler.mIsAwaiting || handler.getState() == GestureHandler.STATE_ACTIVE)) {
|
||||
// in every other case as long as the handler is about to be activated or already in active
|
||||
// state, we delegate the decision to the implementation of GestureHandler#shouldBeCancelledBy
|
||||
return handler.shouldBeCancelledBy(other);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isFinished(int state) {
|
||||
return state == GestureHandler.STATE_CANCELLED || state == GestureHandler.STATE_FAILED
|
||||
|| state == GestureHandler.STATE_END;
|
||||
}
|
||||
}
|
10
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerRegistry.java
generated
vendored
Normal file
10
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerRegistry.java
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface GestureHandlerRegistry {
|
||||
ArrayList<GestureHandler> getHandlersForView(View view);
|
||||
}
|
29
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerRegistryImpl.java
generated
vendored
Normal file
29
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerRegistryImpl.java
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class GestureHandlerRegistryImpl implements GestureHandlerRegistry {
|
||||
|
||||
private WeakHashMap<View, ArrayList<GestureHandler>> mHandlers = new WeakHashMap<>();
|
||||
|
||||
public <T extends GestureHandler> T registerHandlerForView(View view, T handler) {
|
||||
ArrayList<GestureHandler> listToAdd = mHandlers.get(view);
|
||||
if (listToAdd == null) {
|
||||
listToAdd = new ArrayList<>(1);
|
||||
listToAdd.add(handler);
|
||||
mHandlers.put(view, listToAdd);
|
||||
} else {
|
||||
listToAdd.add(handler);
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<GestureHandler> getHandlersForView(View view) {
|
||||
return mHandlers.get(view);
|
||||
}
|
||||
}
|
||||
|
53
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureUtils.java
generated
vendored
Normal file
53
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureUtils.java
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class GestureUtils {
|
||||
public static float getLastPointerX(MotionEvent event, boolean averageTouches) {
|
||||
float offset = event.getRawX() - event.getX();
|
||||
int excludeIndex = event.getActionMasked() == MotionEvent.ACTION_POINTER_UP ?
|
||||
event.getActionIndex() : -1;
|
||||
|
||||
if (averageTouches) {
|
||||
float sum = 0f;
|
||||
int count = 0;
|
||||
for (int i = 0, size = event.getPointerCount(); i < size; i++) {
|
||||
if (i != excludeIndex) {
|
||||
sum += event.getX(i) + offset;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return sum / count;
|
||||
} else {
|
||||
int lastPointerIdx = event.getPointerCount() - 1;
|
||||
if (lastPointerIdx == excludeIndex) {
|
||||
lastPointerIdx--;
|
||||
}
|
||||
return event.getX(lastPointerIdx) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
public static float getLastPointerY(MotionEvent event, boolean averageTouches) {
|
||||
float offset = event.getRawY() - event.getY();
|
||||
int excludeIndex = event.getActionMasked() == MotionEvent.ACTION_POINTER_UP ?
|
||||
event.getActionIndex() : -1;
|
||||
|
||||
if (averageTouches) {
|
||||
float sum = 0f;
|
||||
int count = 0;
|
||||
for (int i = 0, size = event.getPointerCount(); i < size; i++) {
|
||||
if (i != excludeIndex) {
|
||||
sum += event.getY(i) + offset;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return sum / count;
|
||||
} else {
|
||||
int lastPointerIdx = event.getPointerCount() - 1;
|
||||
if (lastPointerIdx == excludeIndex) {
|
||||
lastPointerIdx -= 1;
|
||||
}
|
||||
return event.getY(lastPointerIdx) + offset;
|
||||
}
|
||||
}
|
||||
}
|
77
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java
generated
vendored
Normal file
77
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class LongPressGestureHandler extends GestureHandler<LongPressGestureHandler> {
|
||||
|
||||
private static final long DEFAULT_MIN_DURATION_MS = 500; // 1 sec
|
||||
private static float DEFAULT_MAX_DIST_DP = 10; // 20dp
|
||||
|
||||
private long mMinDurationMs = DEFAULT_MIN_DURATION_MS;
|
||||
private float mMaxDistSq;
|
||||
private float mStartX, mStartY;
|
||||
private Handler mHandler;
|
||||
|
||||
public LongPressGestureHandler(Context context) {
|
||||
setShouldCancelWhenOutside(true);
|
||||
mMaxDistSq = DEFAULT_MAX_DIST_DP * context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public void setMinDurationMs(long minDurationMs) {
|
||||
mMinDurationMs = minDurationMs;
|
||||
}
|
||||
|
||||
public LongPressGestureHandler setMaxDist(float maxDist) {
|
||||
mMaxDistSq = maxDist * maxDist;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
if (getState() == STATE_UNDETERMINED) {
|
||||
begin();
|
||||
mStartX = event.getRawX();
|
||||
mStartY = event.getRawY();
|
||||
mHandler = new Handler();
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
activate();
|
||||
}
|
||||
}, mMinDurationMs);
|
||||
}
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
mHandler = null;
|
||||
}
|
||||
if (getState() == STATE_ACTIVE) {
|
||||
end();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
} else {
|
||||
// calculate distance from start
|
||||
float deltaX = event.getRawX() - mStartX;
|
||||
float deltaY = event.getRawY() - mStartY;
|
||||
float distSq = deltaX * deltaX + deltaY * deltaY;
|
||||
if (distSq > mMaxDistSq) {
|
||||
if (getState() == STATE_ACTIVE) {
|
||||
cancel();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStateChange(int newState, int previousState) {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
mHandler = null;
|
||||
}
|
||||
}
|
||||
}
|
110
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/NativeViewGestureHandler.java
generated
vendored
Normal file
110
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/NativeViewGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class NativeViewGestureHandler extends GestureHandler<NativeViewGestureHandler> {
|
||||
|
||||
private boolean mShouldActivateOnStart;
|
||||
private boolean mDisallowInterruption;
|
||||
|
||||
public NativeViewGestureHandler() {
|
||||
setShouldCancelWhenOutside(true);
|
||||
}
|
||||
|
||||
public NativeViewGestureHandler setShouldActivateOnStart(boolean shouldActivateOnStart) {
|
||||
mShouldActivateOnStart = shouldActivateOnStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to {@code true} when wrapping native components that are supposed to be an exclusive
|
||||
* target for a touch stream. Like for example switch or slider component which when activated
|
||||
* aren't supposed to be cancelled by scrollview or other container that may also handle touches.
|
||||
*/
|
||||
public NativeViewGestureHandler setDisallowInterruption(boolean disallowInterruption) {
|
||||
mDisallowInterruption = disallowInterruption;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRequireToWaitForFailure(GestureHandler handler) {
|
||||
return super.shouldRequireToWaitForFailure(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRecognizeSimultaneously(GestureHandler handler) {
|
||||
if (handler instanceof NativeViewGestureHandler) {
|
||||
// Special case when the peer handler is also an instance of NativeViewGestureHandler:
|
||||
// For the `disallowInterruption` to work correctly we need to check the property when
|
||||
// accessed as a peer, because simultaneous recognizers can be set on either side of the
|
||||
// connection.
|
||||
NativeViewGestureHandler nativeWrapper = (NativeViewGestureHandler) handler;
|
||||
if (nativeWrapper.getState() == STATE_ACTIVE && nativeWrapper.mDisallowInterruption) {
|
||||
// other handler is active and it disallows interruption, we don't want to get into its way
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean canBeInterrupted = !mDisallowInterruption;
|
||||
int state = getState();
|
||||
int otherState = handler.getState();
|
||||
|
||||
if (state == STATE_ACTIVE && otherState == STATE_ACTIVE && canBeInterrupted) {
|
||||
// if both handlers are active and the current handler can be interruped it we return `false`
|
||||
// as it means the other handler has turned active and returning `true` would prevent it from
|
||||
// interrupting the current handler
|
||||
return false;
|
||||
}
|
||||
// otherwise we can only return `true` if already in an active state
|
||||
return state == STATE_ACTIVE && canBeInterrupted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBeCancelledBy(GestureHandler handler) {
|
||||
return !mDisallowInterruption;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
View view = getView();
|
||||
int state = getState();
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
view.onTouchEvent(event);
|
||||
if ((state == STATE_UNDETERMINED || state == STATE_BEGAN) && view.isPressed()) {
|
||||
activate();
|
||||
}
|
||||
end();
|
||||
} else if (state == STATE_UNDETERMINED || state == STATE_BEGAN) {
|
||||
if (mShouldActivateOnStart) {
|
||||
tryIntercept(view, event);
|
||||
view.onTouchEvent(event);
|
||||
activate();
|
||||
} else if (tryIntercept(view, event)) {
|
||||
view.onTouchEvent(event);
|
||||
activate();
|
||||
} else if (state != STATE_BEGAN) {
|
||||
begin();
|
||||
}
|
||||
} else if (state == STATE_ACTIVE) {
|
||||
view.onTouchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean tryIntercept(View view, MotionEvent event) {
|
||||
if (view instanceof ViewGroup && ((ViewGroup) view).onInterceptTouchEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancel() {
|
||||
long time = SystemClock.uptimeMillis();
|
||||
MotionEvent event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
event.setAction(MotionEvent.ACTION_CANCEL);
|
||||
getView().onTouchEvent(event);
|
||||
}
|
||||
}
|
8
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/OnTouchEventListener.java
generated
vendored
Normal file
8
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/OnTouchEventListener.java
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public interface OnTouchEventListener<T extends GestureHandler> {
|
||||
void onTouchEvent(T handler, MotionEvent event);
|
||||
void onStateChange(T handler, int newState, int oldState);
|
||||
}
|
312
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.java
generated
vendored
Normal file
312
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,312 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
public class PanGestureHandler extends GestureHandler<PanGestureHandler> {
|
||||
|
||||
private static float MIN_VALUE_IGNORE = Float.MAX_VALUE;
|
||||
private static float MAX_VALUE_IGNORE = Float.MIN_VALUE;
|
||||
|
||||
private static int DEFAULT_MIN_POINTERS = 1;
|
||||
private static int DEFAULT_MAX_POINTERS = 10;
|
||||
|
||||
private float mMinDistSq = MAX_VALUE_IGNORE;
|
||||
|
||||
private float mActiveOffsetXStart = MIN_VALUE_IGNORE;
|
||||
private float mActiveOffsetXEnd = MAX_VALUE_IGNORE;
|
||||
|
||||
private float mFailOffsetXStart = MAX_VALUE_IGNORE;
|
||||
private float mFailOffsetXEnd = MIN_VALUE_IGNORE;
|
||||
|
||||
private float mActiveOffsetYStart = MIN_VALUE_IGNORE;
|
||||
private float mActiveOffsetYEnd = MAX_VALUE_IGNORE;
|
||||
|
||||
private float mFailOffsetYStart = MAX_VALUE_IGNORE;
|
||||
private float mFailOffsetYEnd = MIN_VALUE_IGNORE;
|
||||
|
||||
private float mMinVelocityX = MIN_VALUE_IGNORE;
|
||||
private float mMinVelocityY = MIN_VALUE_IGNORE;
|
||||
private float mMinVelocitySq = MIN_VALUE_IGNORE;
|
||||
private int mMinPointers = DEFAULT_MIN_POINTERS;
|
||||
private int mMaxPointers = DEFAULT_MAX_POINTERS;
|
||||
|
||||
private float mStartX, mStartY;
|
||||
private float mOffsetX, mOffsetY;
|
||||
private float mLastX, mLastY;
|
||||
private float mLastVelocityX, mLastVelocityY;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
|
||||
private boolean mAverageTouches;
|
||||
|
||||
/**
|
||||
* On Android when there are multiple pointers on the screen pan gestures most often just consider
|
||||
* the last placed pointer. The behaviour on iOS is quite different where the x and y component
|
||||
* of the pan pointer is calculated as an average out of all the pointers placed on the screen.
|
||||
*
|
||||
* This behaviour can be customized on android by setting averageTouches property of the handler
|
||||
* object. This could be useful in particular for the usecases when we attach other handlers that
|
||||
* recognizes multi-finger gestures such as rotation. In that case when we only rely on the last
|
||||
* placed finger it is easier for the gesture handler to trigger when we do a rotation gesture
|
||||
* because each finger when treated separately will travel some distance, whereas the average
|
||||
* position of all the fingers will remain still while doing a rotation gesture.
|
||||
*/
|
||||
public PanGestureHandler(Context context) {
|
||||
ViewConfiguration vc = ViewConfiguration.get(context);
|
||||
int touchSlop = vc.getScaledTouchSlop();
|
||||
mMinDistSq = touchSlop * touchSlop;
|
||||
}
|
||||
|
||||
public PanGestureHandler setActiveOffsetXStart(float activeOffsetXStart) {
|
||||
mActiveOffsetXStart = activeOffsetXStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setActiveOffsetXEnd(float activeOffsetXEnd) {
|
||||
mActiveOffsetXEnd = activeOffsetXEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setFailOffsetXStart(float failOffsetXStart) {
|
||||
mFailOffsetXStart = failOffsetXStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setFailOffsetXEnd(float failOffsetXEnd) {
|
||||
mFailOffsetXEnd = failOffsetXEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setActiveOffsetYStart(float activeOffsetYStart) {
|
||||
mActiveOffsetYStart = activeOffsetYStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setActiveOffsetYEnd(float activeOffsetYEnd) {
|
||||
mActiveOffsetYEnd = activeOffsetYEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setFailOffsetYStart(float failOffsetYStart) {
|
||||
mFailOffsetYStart = failOffsetYStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setFailOffsetYEnd(float failOffsetYEnd) {
|
||||
mFailOffsetYEnd = failOffsetYEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setMinDist(float minDist) {
|
||||
mMinDistSq = minDist * minDist;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setMinPointers(int minPointers) {
|
||||
mMinPointers = minPointers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setMaxPointers(int maxPointers) {
|
||||
mMaxPointers = maxPointers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setAverageTouches(boolean averageTouches) {
|
||||
mAverageTouches = averageTouches;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minVelocity in pixels per second
|
||||
*/
|
||||
public PanGestureHandler setMinVelocity(float minVelocity) {
|
||||
mMinVelocitySq = minVelocity * minVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setMinVelocityX(float minVelocityX) {
|
||||
mMinVelocityX = minVelocityX;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PanGestureHandler setMinVelocityY(float minVelocityY) {
|
||||
mMinVelocityY = minVelocityY;
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean shouldActivate() {
|
||||
float dx = mLastX - mStartX + mOffsetX;
|
||||
if (mActiveOffsetXStart != MIN_VALUE_IGNORE && dx < mActiveOffsetXStart) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mActiveOffsetXEnd != MAX_VALUE_IGNORE && dx > mActiveOffsetXEnd) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float dy = mLastY - mStartY + mOffsetY;
|
||||
if (mActiveOffsetYStart != MIN_VALUE_IGNORE && dy < mActiveOffsetYStart) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mActiveOffsetYEnd != MAX_VALUE_IGNORE && dy > mActiveOffsetYEnd) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float distSq = dx * dx + dy * dy;
|
||||
if (mMinDistSq != MIN_VALUE_IGNORE && distSq >= mMinDistSq) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float vx = mLastVelocityX;
|
||||
if (mMinVelocityX != MIN_VALUE_IGNORE &&
|
||||
((mMinVelocityX < 0 && vx <= mMinVelocityX) || (mMinVelocityX >= 0 && vx >= mMinVelocityX))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float vy = mLastVelocityY;
|
||||
if (mMinVelocityY != MIN_VALUE_IGNORE &&
|
||||
((mMinVelocityY < 0 && vx <= mMinVelocityY) || (mMinVelocityY >= 0 && vx >= mMinVelocityY))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float velocitySq = vx * vx + vy * vy;
|
||||
if (mMinVelocitySq != MIN_VALUE_IGNORE && velocitySq >= mMinVelocitySq) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldFail() {
|
||||
float dx = mLastX - mStartX + mOffsetX;
|
||||
|
||||
if (mFailOffsetXStart != MAX_VALUE_IGNORE && dx < mFailOffsetXStart) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mFailOffsetXEnd != MIN_VALUE_IGNORE && dx > mFailOffsetXEnd) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
float dy = mLastY - mStartY + mOffsetY;
|
||||
if (mFailOffsetYStart != MAX_VALUE_IGNORE && dy < mFailOffsetYStart) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mFailOffsetYEnd != MIN_VALUE_IGNORE && dy > mFailOffsetYEnd) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
int state = getState();
|
||||
int action = event.getActionMasked();
|
||||
|
||||
if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
// update offset if new pointer gets added or removed
|
||||
mOffsetX += mLastX - mStartX;
|
||||
mOffsetY += mLastY - mStartY;
|
||||
|
||||
// reset starting point
|
||||
mLastX = GestureUtils.getLastPointerX(event, mAverageTouches);
|
||||
mLastY = GestureUtils.getLastPointerY(event, mAverageTouches);
|
||||
mStartX = mLastX;
|
||||
mStartY = mLastY;
|
||||
} else {
|
||||
mLastX = GestureUtils.getLastPointerX(event, mAverageTouches);
|
||||
mLastY = GestureUtils.getLastPointerY(event, mAverageTouches);
|
||||
}
|
||||
|
||||
if (state == STATE_UNDETERMINED && event.getPointerCount() >= mMinPointers) {
|
||||
mStartX = mLastX;
|
||||
mStartY = mLastY;
|
||||
mOffsetX = 0;
|
||||
mOffsetY = 0;
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
addVelocityMovement(mVelocityTracker, event);
|
||||
begin();
|
||||
} else if (mVelocityTracker != null) {
|
||||
addVelocityMovement(mVelocityTracker, event);
|
||||
mVelocityTracker.computeCurrentVelocity(1000);
|
||||
mLastVelocityX = mVelocityTracker.getXVelocity();
|
||||
mLastVelocityY = mVelocityTracker.getYVelocity();
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
if (state == STATE_ACTIVE || state == STATE_BEGAN) {
|
||||
end();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
} else if (action == MotionEvent.ACTION_POINTER_DOWN && event.getPointerCount() > mMaxPointers) {
|
||||
// When new finger is placed down (POINTER_DOWN) we check if MAX_POINTERS is not exceeded
|
||||
if (state == STATE_ACTIVE) {
|
||||
cancel();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
} else if (action == MotionEvent.ACTION_POINTER_UP && state == STATE_ACTIVE
|
||||
&& event.getPointerCount() < mMinPointers) {
|
||||
// When finger is lifted up (POINTER_UP) and the number of pointers falls below MIN_POINTERS
|
||||
// threshold, we only want to take an action when the handler has already activated. Otherwise
|
||||
// we can still expect more fingers to be placed on screen and fulfill MIN_POINTERS criteria.
|
||||
fail();
|
||||
} else if (state == STATE_BEGAN) {
|
||||
if (shouldFail()) {
|
||||
fail();
|
||||
} else if (shouldActivate()) {
|
||||
// reset starting point
|
||||
mStartX = mLastX;
|
||||
mStartY = mLastY;
|
||||
activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
public float getTranslationX() {
|
||||
return mLastX - mStartX + mOffsetX;
|
||||
}
|
||||
|
||||
public float getTranslationY() {
|
||||
return mLastY - mStartY + mOffsetY;
|
||||
}
|
||||
|
||||
public float getVelocityX() {
|
||||
return mLastVelocityX;
|
||||
}
|
||||
|
||||
public float getVelocityY() {
|
||||
return mLastVelocityY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method adds movement to {@class VelocityTracker} first resetting offset of the event so
|
||||
* that the velocity is calculated based on the absolute position of touch pointers. This is
|
||||
* because if the underlying view moves along with the finger using relative x/y coords yields
|
||||
* incorrect results.
|
||||
*/
|
||||
private static void addVelocityMovement(VelocityTracker tracker, MotionEvent event) {
|
||||
float offsetX = event.getRawX() - event.getX();
|
||||
float offsetY = event.getRawY() - event.getY();
|
||||
event.offsetLocation(offsetX, offsetY);
|
||||
tracker.addMovement(event);
|
||||
event.offsetLocation(-offsetX, -offsetY);
|
||||
}
|
||||
}
|
109
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/PinchGestureHandler.java
generated
vendored
Normal file
109
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/PinchGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
public class PinchGestureHandler extends GestureHandler<PinchGestureHandler> {
|
||||
|
||||
private ScaleGestureDetector mScaleGestureDetector;
|
||||
private double mLastScaleFactor;
|
||||
private double mLastVelocity;
|
||||
|
||||
private float mStartingSpan;
|
||||
private float mSpanSlop;
|
||||
|
||||
private ScaleGestureDetector.OnScaleGestureListener mGestureListener =
|
||||
new ScaleGestureDetector.OnScaleGestureListener() {
|
||||
|
||||
@Override
|
||||
public boolean onScale(ScaleGestureDetector detector) {
|
||||
double prevScaleFactor = mLastScaleFactor;
|
||||
mLastScaleFactor *= detector.getScaleFactor();
|
||||
long delta = detector.getTimeDelta();
|
||||
if (delta > 0) {
|
||||
mLastVelocity = (mLastScaleFactor - prevScaleFactor) / delta;
|
||||
}
|
||||
if (Math.abs(mStartingSpan - detector.getCurrentSpan()) >= mSpanSlop
|
||||
&& getState() == STATE_BEGAN) {
|
||||
activate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
||||
mStartingSpan = detector.getCurrentSpan();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScaleEnd(ScaleGestureDetector detector) {
|
||||
// ScaleGestureDetector thinks that when fingers are 27mm away that's a sufficiently good
|
||||
// reason to trigger this method giving us no other choice but to ignore it completely.
|
||||
}
|
||||
};
|
||||
|
||||
public PinchGestureHandler() {
|
||||
setShouldCancelWhenOutside(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
if (getState() == STATE_UNDETERMINED) {
|
||||
Context context = getView().getContext();
|
||||
mLastVelocity = 0f;
|
||||
mLastScaleFactor = 1f;
|
||||
mScaleGestureDetector = new ScaleGestureDetector(context, mGestureListener);
|
||||
ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||
mSpanSlop = configuration.getScaledTouchSlop();
|
||||
|
||||
begin();
|
||||
}
|
||||
|
||||
if (mScaleGestureDetector != null) {
|
||||
mScaleGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
int activePointers = event.getPointerCount();
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
|
||||
activePointers -= 1;
|
||||
}
|
||||
|
||||
if (getState() == STATE_ACTIVE && activePointers < 2) {
|
||||
end();
|
||||
} else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
mScaleGestureDetector = null;
|
||||
mLastVelocity = 0f;
|
||||
mLastScaleFactor = 1f;
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return mLastScaleFactor;
|
||||
}
|
||||
|
||||
public double getVelocity() {
|
||||
return mLastVelocity;
|
||||
}
|
||||
|
||||
public float getFocalPointX() {
|
||||
if (mScaleGestureDetector == null) {
|
||||
return Float.NaN;
|
||||
}
|
||||
return mScaleGestureDetector.getFocusX();
|
||||
}
|
||||
|
||||
public float getFocalPointY() {
|
||||
if (mScaleGestureDetector == null) {
|
||||
return Float.NaN;
|
||||
}
|
||||
return mScaleGestureDetector.getFocusY();
|
||||
}
|
||||
}
|
25
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/PointerEventsConfig.java
generated
vendored
Normal file
25
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/PointerEventsConfig.java
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
public enum PointerEventsConfig {
|
||||
|
||||
/**
|
||||
* Neither the container nor its children receive events.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Container doesn't get events but all of its children do.
|
||||
*/
|
||||
BOX_NONE,
|
||||
|
||||
/**
|
||||
* Container gets events but none of its children do.
|
||||
*/
|
||||
BOX_ONLY,
|
||||
|
||||
/**
|
||||
* Container and all of its children receive touch events (like pointerEvents is unspecified).
|
||||
*/
|
||||
AUTO,
|
||||
;
|
||||
}
|
169
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/RotationGestureDetector.java
generated
vendored
Normal file
169
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/RotationGestureDetector.java
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class RotationGestureDetector {
|
||||
|
||||
public interface OnRotationGestureListener {
|
||||
|
||||
boolean onRotation(RotationGestureDetector detector);
|
||||
|
||||
boolean onRotationBegin(RotationGestureDetector detector);
|
||||
|
||||
void onRotationEnd(RotationGestureDetector detector);
|
||||
}
|
||||
|
||||
private long mCurrTime;
|
||||
private long mPrevTime;
|
||||
private double mPrevAngle;
|
||||
private double mAngleDiff;
|
||||
private float mAnchorX;
|
||||
private float mAnchorY;
|
||||
|
||||
private boolean mInProgress;
|
||||
|
||||
private int mPointerIds[] = new int[2];
|
||||
|
||||
private OnRotationGestureListener mListener;
|
||||
|
||||
public RotationGestureDetector(OnRotationGestureListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private void updateCurrent(MotionEvent event) {
|
||||
mPrevTime = mCurrTime;
|
||||
mCurrTime = event.getEventTime();
|
||||
|
||||
int firstPointerIndex = event.findPointerIndex(mPointerIds[0]);
|
||||
int secondPointerIndex = event.findPointerIndex(mPointerIds[1]);
|
||||
|
||||
float firstPtX = event.getX(firstPointerIndex);
|
||||
float firstPtY = event.getY(firstPointerIndex);
|
||||
float secondPtX = event.getX(secondPointerIndex);
|
||||
float secondPtY = event.getY(secondPointerIndex);
|
||||
|
||||
float vectorX = secondPtX - firstPtX;
|
||||
float vectorY = secondPtY - firstPtY;
|
||||
|
||||
mAnchorX = (firstPtX + secondPtX) * 0.5f;
|
||||
mAnchorY = (firstPtY + secondPtY) * 0.5f;
|
||||
|
||||
// Angle diff should be positive when rotating in clockwise direction
|
||||
double angle = -Math.atan2(vectorY, vectorX);
|
||||
|
||||
if (Double.isNaN(mPrevAngle)) {
|
||||
mAngleDiff = 0.;
|
||||
} else {
|
||||
mAngleDiff = mPrevAngle - angle;
|
||||
}
|
||||
mPrevAngle = angle;
|
||||
|
||||
if (mAngleDiff > Math.PI) {
|
||||
mAngleDiff -= Math.PI;
|
||||
} else if (mAngleDiff < -Math.PI) {
|
||||
mAngleDiff += Math.PI;
|
||||
}
|
||||
|
||||
if (mAngleDiff > Math.PI / 2.) {
|
||||
mAngleDiff -= Math.PI;
|
||||
} else if (mAngleDiff < -Math.PI / 2.) {
|
||||
mAngleDiff += Math.PI;
|
||||
}
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
if (mInProgress) {
|
||||
mInProgress = false;
|
||||
if (mListener != null) {
|
||||
mListener.onRotationEnd(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getActionMasked()) {
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mInProgress = false;
|
||||
mPointerIds[0] = event.getPointerId(event.getActionIndex());
|
||||
mPointerIds[1] = MotionEvent.INVALID_POINTER_ID;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (!mInProgress) {
|
||||
mPointerIds[1] = event.getPointerId(event.getActionIndex());
|
||||
mInProgress = true;
|
||||
mPrevTime = event.getEventTime();
|
||||
mPrevAngle = Double.NaN;
|
||||
updateCurrent(event);
|
||||
if (mListener != null) {
|
||||
mListener.onRotationBegin(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mInProgress) {
|
||||
updateCurrent(event);
|
||||
if (mListener != null) {
|
||||
mListener.onRotation(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (mInProgress) {
|
||||
int pointerId = event.getPointerId(event.getActionIndex());
|
||||
if (pointerId == mPointerIds[0] || pointerId == mPointerIds[1]) {
|
||||
// One of the key pointer has been lifted up, we have to end the gesture
|
||||
finish();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns rotation in radians since the previous rotation event.
|
||||
*
|
||||
* @return current rotation step in radians.
|
||||
*/
|
||||
public double getRotation() {
|
||||
return mAngleDiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time difference in milliseconds between the previous
|
||||
* accepted rotation event and the current rotation event.
|
||||
*
|
||||
* @return Time difference since the last rotation event in milliseconds.
|
||||
*/
|
||||
public long getTimeDelta() {
|
||||
return mCurrTime - mPrevTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns X coordinate of the rotation anchor point relative to the view that the provided motion
|
||||
* event coordinates (usually relative to the view event was sent to).
|
||||
*
|
||||
* @return X coordinate of the rotation anchor point
|
||||
*/
|
||||
public float getAnchorX() {
|
||||
return mAnchorX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Y coordinate of the rotation anchor point relative to the view that the provided motion
|
||||
* event coordinates (usually relative to the view event was sent to).
|
||||
*
|
||||
* @return Y coordinate of the rotation anchor point
|
||||
*/
|
||||
public float getAnchorY() {
|
||||
return mAnchorY;
|
||||
}
|
||||
}
|
96
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/RotationGestureHandler.java
generated
vendored
Normal file
96
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/RotationGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class RotationGestureHandler extends GestureHandler<RotationGestureHandler> {
|
||||
|
||||
private static final double ROTATION_RECOGNITION_THRESHOLD = Math.PI / 36.; // 5 deg in radians
|
||||
|
||||
private RotationGestureDetector mRotationGestureDetector;
|
||||
private double mLastRotation;
|
||||
private double mLastVelocity;
|
||||
|
||||
private RotationGestureDetector.OnRotationGestureListener mGestureListener = new RotationGestureDetector.OnRotationGestureListener() {
|
||||
|
||||
@Override
|
||||
public boolean onRotation(RotationGestureDetector detector) {
|
||||
double prevRotation = mLastRotation;
|
||||
mLastRotation += detector.getRotation();
|
||||
long delta = detector.getTimeDelta();
|
||||
if (delta > 0) {
|
||||
mLastVelocity = (mLastRotation - prevRotation) / delta;
|
||||
}
|
||||
if (Math.abs(mLastRotation) >= ROTATION_RECOGNITION_THRESHOLD && getState() == STATE_BEGAN) {
|
||||
activate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRotationBegin(RotationGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRotationEnd(RotationGestureDetector detector) {
|
||||
end();
|
||||
}
|
||||
};
|
||||
|
||||
public RotationGestureHandler() {
|
||||
setShouldCancelWhenOutside(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
int state = getState();
|
||||
if (state == STATE_UNDETERMINED) {
|
||||
mLastVelocity = 0f;
|
||||
mLastRotation = 0f;
|
||||
mRotationGestureDetector = new RotationGestureDetector(mGestureListener);
|
||||
|
||||
begin();
|
||||
}
|
||||
|
||||
if (mRotationGestureDetector != null) {
|
||||
mRotationGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
if (state == STATE_ACTIVE) {
|
||||
end();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
mRotationGestureDetector = null;
|
||||
mLastVelocity = 0f;
|
||||
mLastRotation = 0f;
|
||||
}
|
||||
|
||||
public double getRotation() {
|
||||
return mLastRotation;
|
||||
}
|
||||
|
||||
public double getVelocity() {
|
||||
return mLastVelocity;
|
||||
}
|
||||
|
||||
public float getAnchorX() {
|
||||
if (mRotationGestureDetector == null) {
|
||||
return Float.NaN;
|
||||
}
|
||||
return mRotationGestureDetector.getAnchorX();
|
||||
}
|
||||
|
||||
public float getAnchorY() {
|
||||
if (mRotationGestureDetector == null) {
|
||||
return Float.NaN;
|
||||
}
|
||||
return mRotationGestureDetector.getAnchorY();
|
||||
}
|
||||
}
|
172
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/TapGestureHandler.java
generated
vendored
Normal file
172
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/TapGestureHandler.java
generated
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class TapGestureHandler extends GestureHandler<TapGestureHandler> {
|
||||
private static float MAX_VALUE_IGNORE = Float.MIN_VALUE;
|
||||
private static final long DEFAULT_MAX_DURATION_MS = 500;
|
||||
private static final long DEFAULT_MAX_DELAY_MS = 500;
|
||||
private static final int DEFAULT_NUMBER_OF_TAPS = 1;
|
||||
private static final int DEFAULT_MIN_NUMBER_OF_POINTERS = 1;
|
||||
|
||||
private float mMaxDeltaX = MAX_VALUE_IGNORE;
|
||||
private float mMaxDeltaY = MAX_VALUE_IGNORE;
|
||||
private float mMaxDistSq = MAX_VALUE_IGNORE;
|
||||
|
||||
private long mMaxDurationMs = DEFAULT_MAX_DURATION_MS;
|
||||
private long mMaxDelayMs = DEFAULT_MAX_DELAY_MS;
|
||||
private int mNumberOfTaps = DEFAULT_NUMBER_OF_TAPS;
|
||||
private int mMinNumberOfPointers = DEFAULT_MIN_NUMBER_OF_POINTERS;
|
||||
private int mNumberOfPointers = 1;
|
||||
|
||||
private float mStartX, mStartY;
|
||||
private float mOffsetX, mOffsetY;
|
||||
private float mLastX, mLastY;
|
||||
|
||||
private Handler mHandler;
|
||||
private int mTapsSoFar;
|
||||
|
||||
private final Runnable mFailDelayed = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fail();
|
||||
}
|
||||
};
|
||||
|
||||
public TapGestureHandler setNumberOfTaps(int numberOfTaps) {
|
||||
mNumberOfTaps = numberOfTaps;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TapGestureHandler setMaxDelayMs(long maxDelayMs) {
|
||||
mMaxDelayMs = maxDelayMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TapGestureHandler setMaxDurationMs(long maxDurationMs) {
|
||||
mMaxDurationMs = maxDurationMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TapGestureHandler setMaxDx(float deltaX) {
|
||||
mMaxDeltaX = deltaX;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TapGestureHandler setMaxDy(float deltaY) {
|
||||
mMaxDeltaY = deltaY;
|
||||
return this;
|
||||
}
|
||||
public TapGestureHandler setMaxDist(float maxDist) {
|
||||
mMaxDistSq = maxDist * maxDist;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TapGestureHandler setMinNumberOfPointers(int minNumberOfPointers) {
|
||||
mMinNumberOfPointers = minNumberOfPointers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TapGestureHandler() {
|
||||
setShouldCancelWhenOutside(true);
|
||||
}
|
||||
|
||||
private void startTap() {
|
||||
if (mHandler == null) {
|
||||
mHandler = new Handler();
|
||||
} else {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
mHandler.postDelayed(mFailDelayed, mMaxDurationMs);
|
||||
}
|
||||
|
||||
private void endTap() {
|
||||
if (mHandler == null) {
|
||||
mHandler = new Handler();
|
||||
} else {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
if (++mTapsSoFar == mNumberOfTaps && mNumberOfPointers >= mMinNumberOfPointers) {
|
||||
activate();
|
||||
end();
|
||||
} else {
|
||||
mHandler.postDelayed(mFailDelayed, mMaxDelayMs);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldFail() {
|
||||
float dx = mLastX - mStartX + mOffsetX;
|
||||
if (mMaxDeltaX != MAX_VALUE_IGNORE && Math.abs(dx) > mMaxDeltaX) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float dy = mLastY - mStartY + mOffsetY;
|
||||
if (mMaxDeltaY != MAX_VALUE_IGNORE && Math.abs(dy) > mMaxDeltaY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float dist = dy * dy + dx * dx;
|
||||
return mMaxDistSq != MAX_VALUE_IGNORE && dist > mMaxDistSq;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
int state = getState();
|
||||
int action = event.getActionMasked();
|
||||
|
||||
if (state == STATE_UNDETERMINED) {
|
||||
mOffsetX = 0;
|
||||
mOffsetY = 0;
|
||||
mStartX = event.getRawX();
|
||||
mStartY = event.getRawY();
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
mOffsetX += mLastX - mStartX;
|
||||
mOffsetY += mLastY - mStartY;
|
||||
mLastX = GestureUtils.getLastPointerX(event, true);
|
||||
mLastY = GestureUtils.getLastPointerY(event, true);
|
||||
mStartX = mLastX;
|
||||
mStartY = mLastY;
|
||||
} else {
|
||||
mLastX = GestureUtils.getLastPointerX(event, true);
|
||||
mLastY = GestureUtils.getLastPointerY(event, true);
|
||||
}
|
||||
|
||||
if (mNumberOfPointers < event.getPointerCount()) {
|
||||
mNumberOfPointers = event.getPointerCount();
|
||||
}
|
||||
|
||||
if (shouldFail()) {
|
||||
fail();
|
||||
} else if (state == STATE_UNDETERMINED) {
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
begin();
|
||||
}
|
||||
startTap();
|
||||
} else if (state == STATE_BEGAN) {
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
endTap();
|
||||
} else if (action == MotionEvent.ACTION_DOWN) {
|
||||
startTap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancel() {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
mTapsSoFar = 0;
|
||||
mNumberOfPointers = 0;
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
}
|
10
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/ViewConfigurationHelper.java
generated
vendored
Normal file
10
node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/ViewConfigurationHelper.java
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
package com.swmansion.gesturehandler;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public interface ViewConfigurationHelper {
|
||||
PointerEventsConfig getPointerEventsConfigForView(View view);
|
||||
View getChildInDrawingOrderAtIndex(ViewGroup parent, int index);
|
||||
boolean isViewClippingChildren(ViewGroup view);
|
||||
}
|
Reference in New Issue
Block a user