yeet
This commit is contained in:
28
node_modules/react-native-gesture-handler/android/build.gradle
generated
vendored
Normal file
28
node_modules/react-native-gesture-handler/android/build.gradle
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
def safeExtGet(prop, fallback) {
|
||||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion safeExtGet("compileSdkVersion", 28)
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion safeExtGet('minSdkVersion', 16)
|
||||
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
// Include "lib/" as sources, unfortunetely react-native link can't handle
|
||||
// setting up alternative gradle modules. We still have "lib" defined as a
|
||||
// standalone gradle module just to be used in AndroidNativeExample
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'lib/src/main/java'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation 'com.facebook.react:react-native:+'
|
||||
}
|
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);
|
||||
}
|
3
node_modules/react-native-gesture-handler/android/src/main/AndroidManifest.xml
generated
vendored
Normal file
3
node_modules/react-native-gesture-handler/android/src/main/AndroidManifest.xml
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.swmansion.gesturehandler.react">
|
||||
</manifest>
|
21
node_modules/react-native-gesture-handler/android/src/main/java/com/facebook/react/views/modal/RNGHModalUtils.java
generated
vendored
Normal file
21
node_modules/react-native-gesture-handler/android/src/main/java/com/facebook/react/views/modal/RNGHModalUtils.java
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
/**
|
||||
* For handling gestures inside RNGH we need to have access to some methods of
|
||||
* `ReactModalHostView.DialogRootViewGroup`. This class is not available outside
|
||||
* package so this file exports important features.
|
||||
*/
|
||||
|
||||
public class RNGHModalUtils {
|
||||
public static void dialogRootViewGroupOnChildStartedNativeGesture(ViewGroup modal, MotionEvent androidEvent) {
|
||||
((ReactModalHostView.DialogRootViewGroup) modal).onChildStartedNativeGesture(androidEvent);
|
||||
}
|
||||
|
||||
public static boolean isDialogRootViewGroup(ViewParent modal) {
|
||||
return modal instanceof ReactModalHostView.DialogRootViewGroup;
|
||||
}
|
||||
}
|
261
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.java
generated
vendored
Normal file
261
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.java
generated
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.graphics.drawable.PaintDrawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.bridge.SoftAssertions;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
|
||||
public class RNGestureHandlerButtonViewManager extends
|
||||
ViewGroupManager<RNGestureHandlerButtonViewManager.ButtonViewGroup> {
|
||||
|
||||
static class ButtonViewGroup extends ViewGroup {
|
||||
|
||||
static TypedValue sResolveOutValue = new TypedValue();
|
||||
static ButtonViewGroup sResponder;
|
||||
|
||||
int mBackgroundColor = Color.TRANSPARENT;
|
||||
// Using object because of handling null representing no value set.
|
||||
Integer mRippleColor;
|
||||
Integer mRippleRadius;
|
||||
boolean mUseForeground = false;
|
||||
boolean mUseBorderless = false;
|
||||
float mBorderRadius = 0;
|
||||
boolean mNeedBackgroundUpdate = false;
|
||||
public static final String SELECTABLE_ITEM_BACKGROUND = "selectableItemBackground";
|
||||
public static final String SELECTABLE_ITEM_BACKGROUND_BORDERLESS = "selectableItemBackgroundBorderless";
|
||||
|
||||
|
||||
public ButtonViewGroup(Context context) {
|
||||
super(context);
|
||||
|
||||
setClickable(true);
|
||||
setFocusable(true);
|
||||
|
||||
mNeedBackgroundUpdate = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(int color) {
|
||||
mBackgroundColor = color;
|
||||
mNeedBackgroundUpdate = true;
|
||||
}
|
||||
|
||||
public void setRippleColor(Integer color) {
|
||||
mRippleColor = color;
|
||||
mNeedBackgroundUpdate = true;
|
||||
}
|
||||
|
||||
public void setRippleRadius(Integer radius) {
|
||||
mRippleRadius = radius;
|
||||
mNeedBackgroundUpdate = true;
|
||||
}
|
||||
|
||||
public void setBorderRadius(float borderRadius) {
|
||||
mBorderRadius = borderRadius * getResources().getDisplayMetrics().density;
|
||||
mNeedBackgroundUpdate = true;
|
||||
}
|
||||
|
||||
private Drawable applyRippleEffectWhenNeeded(Drawable selectable) {
|
||||
if (mRippleColor != null
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
&& selectable instanceof RippleDrawable) {
|
||||
int[][] states = new int[][]{ new int[]{ android.R.attr.state_enabled } };
|
||||
int[] colors = new int[]{ mRippleColor };
|
||||
ColorStateList colorStateList = new ColorStateList(states, colors);
|
||||
((RippleDrawable) selectable).setColor(colorStateList);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& mRippleRadius != null
|
||||
&& selectable instanceof RippleDrawable) {
|
||||
RippleDrawable rippleDrawable = (RippleDrawable) selectable;
|
||||
rippleDrawable.setRadius((int) PixelUtil.toPixelFromDIP(mRippleRadius));
|
||||
}
|
||||
return selectable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (super.onInterceptTouchEvent(ev)) {
|
||||
return true;
|
||||
}
|
||||
// We call `onTouchEvent` to and wait until button changes state to `pressed`, if it's pressed
|
||||
// we return true so that the gesture handler can activate
|
||||
onTouchEvent(ev);
|
||||
return isPressed();
|
||||
}
|
||||
|
||||
private void updateBackground() {
|
||||
if (!mNeedBackgroundUpdate) {
|
||||
return;
|
||||
}
|
||||
mNeedBackgroundUpdate = false;
|
||||
if (mBackgroundColor == Color.TRANSPARENT) {
|
||||
// reset background
|
||||
setBackground(null);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// reset foreground
|
||||
setForeground(null);
|
||||
}
|
||||
if (mUseForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setForeground(applyRippleEffectWhenNeeded(createSelectableDrawable()));
|
||||
if (mBackgroundColor != Color.TRANSPARENT) {
|
||||
setBackgroundColor(mBackgroundColor);
|
||||
}
|
||||
} else if (mBackgroundColor == Color.TRANSPARENT && mRippleColor == null) {
|
||||
setBackground(createSelectableDrawable());
|
||||
} else {
|
||||
PaintDrawable colorDrawable = new PaintDrawable(mBackgroundColor);
|
||||
Drawable selectable = createSelectableDrawable();
|
||||
if (mBorderRadius != 0) {
|
||||
// Radius-connected lines below ought to be considered
|
||||
// as a temporary solution. It do not allow to set
|
||||
// different radius on each corner. However, I suppose it's fairly
|
||||
// fine for button-related use cases.
|
||||
// Therefore it might be used as long as:
|
||||
// 1. ReactViewManager is not a generic class with a possibility to handle another ViewGroup
|
||||
// 2. There's no way to force native behavior of ReactViewGroup's superclass's onTouchEvent
|
||||
colorDrawable.setCornerRadius(mBorderRadius);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
&& selectable instanceof RippleDrawable) {
|
||||
PaintDrawable mask = new PaintDrawable(Color.WHITE);
|
||||
mask.setCornerRadius(mBorderRadius);
|
||||
((RippleDrawable) selectable).setDrawableByLayerId(android.R.id.mask, mask);
|
||||
}
|
||||
}
|
||||
applyRippleEffectWhenNeeded(selectable);
|
||||
LayerDrawable layerDrawable = new LayerDrawable(
|
||||
new Drawable[] { colorDrawable, selectable});
|
||||
setBackground(layerDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseDrawableOnForeground(boolean useForeground) {
|
||||
mUseForeground = useForeground;
|
||||
mNeedBackgroundUpdate = true;
|
||||
}
|
||||
|
||||
public void setUseBorderlessDrawable(boolean useBorderless) {
|
||||
mUseBorderless = useBorderless;
|
||||
}
|
||||
|
||||
private Drawable createSelectableDrawable() {
|
||||
final int version = Build.VERSION.SDK_INT;
|
||||
String identifier = mUseBorderless && version >= 21 ? SELECTABLE_ITEM_BACKGROUND_BORDERLESS
|
||||
: SELECTABLE_ITEM_BACKGROUND;
|
||||
int attrID = getAttrId(getContext(), identifier);
|
||||
getContext().getTheme().resolveAttribute(attrID, sResolveOutValue, true);
|
||||
if (version >= 21) {
|
||||
return getResources().getDrawable(sResolveOutValue.resourceId, getContext().getTheme());
|
||||
} else {
|
||||
return getResources().getDrawable(sResolveOutValue.resourceId);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private static int getAttrId(Context context, String attr) {
|
||||
SoftAssertions.assertNotNull(attr);
|
||||
if (SELECTABLE_ITEM_BACKGROUND.equals(attr)) {
|
||||
return android.R.attr.selectableItemBackground;
|
||||
} else if (SELECTABLE_ITEM_BACKGROUND_BORDERLESS.equals(attr)) {
|
||||
return android.R.attr.selectableItemBackgroundBorderless;
|
||||
} else {
|
||||
return context.getResources().getIdentifier(attr, "attr", "android");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawableHotspotChanged(float x, float y) {
|
||||
if (sResponder == null || sResponder == this) {
|
||||
super.drawableHotspotChanged(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPressed(boolean pressed) {
|
||||
if (pressed && sResponder == null) {
|
||||
// first button to be pressed grabs button responder
|
||||
sResponder = this;
|
||||
}
|
||||
if (!pressed || sResponder == this) {
|
||||
// we set pressed state only for current responder
|
||||
super.setPressed(pressed);
|
||||
}
|
||||
if (!pressed && sResponder == this) {
|
||||
// if the responder is no longer pressed we release button responder
|
||||
sResponder = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDrawableHotspotChanged(float x, float y) {
|
||||
// by default viewgroup would pass hotspot change events
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNGestureHandlerButton";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ButtonViewGroup createViewInstance(ThemedReactContext context) {
|
||||
return new ButtonViewGroup(context);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
@ReactProp(name = "foreground")
|
||||
public void setForeground(ButtonViewGroup view, boolean useDrawableOnForeground) {
|
||||
view.setUseDrawableOnForeground(useDrawableOnForeground);
|
||||
}
|
||||
|
||||
@ReactProp(name = "borderless")
|
||||
public void setBorderless(ButtonViewGroup view, boolean useBorderlessDrawable) {
|
||||
view.setUseBorderlessDrawable(useBorderlessDrawable);
|
||||
}
|
||||
|
||||
@ReactProp(name = "enabled")
|
||||
public void setEnabled(ButtonViewGroup view, boolean enabled) {
|
||||
view.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.BORDER_RADIUS)
|
||||
public void setBorderRadius(ButtonViewGroup view, float borderRadius) {
|
||||
view.setBorderRadius(borderRadius);
|
||||
}
|
||||
|
||||
@ReactProp(name = "rippleColor")
|
||||
public void setRippleColor(ButtonViewGroup view, Integer rippleColor) {
|
||||
view.setRippleColor(rippleColor);
|
||||
}
|
||||
|
||||
@ReactProp(name = "rippleRadius")
|
||||
public void setRippleRadius(ButtonViewGroup view, Integer rippleRadius) {
|
||||
view.setRippleRadius(rippleRadius);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterUpdateTransaction(ButtonViewGroup view) {
|
||||
view.updateBackground();
|
||||
}
|
||||
}
|
72
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.java
generated
vendored
Normal file
72
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.java
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactRootView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class RNGestureHandlerEnabledRootView extends ReactRootView {
|
||||
|
||||
private @Nullable ReactInstanceManager mReactInstanceManager;
|
||||
private @Nullable RNGestureHandlerRootHelper mGestureRootHelper;
|
||||
|
||||
public RNGestureHandlerEnabledRootView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public RNGestureHandlerEnabledRootView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
if (mGestureRootHelper != null) {
|
||||
mGestureRootHelper.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
super.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (mGestureRootHelper != null && mGestureRootHelper.dispatchTouchEvent(ev)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to enable root view to start processing touch events through the gesture
|
||||
* handler library logic. Unless this method is called (which happens as a result of instantiating
|
||||
* new gesture handler from JS) the root view component will just proxy all touch related methods
|
||||
* to its superclass. Thus in the "disabled" state all touch related events will fallback to
|
||||
* default RN behavior.
|
||||
*/
|
||||
public void initialize() {
|
||||
if (mGestureRootHelper != null) {
|
||||
throw new IllegalStateException("GestureHandler already initialized for root view " + this);
|
||||
}
|
||||
mGestureRootHelper = new RNGestureHandlerRootHelper(
|
||||
mReactInstanceManager.getCurrentReactContext(), this);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
if (mGestureRootHelper != null) {
|
||||
mGestureRootHelper.tearDown();
|
||||
mGestureRootHelper = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startReactApplication(
|
||||
ReactInstanceManager reactInstanceManager,
|
||||
String moduleName,
|
||||
@Nullable Bundle initialProperties) {
|
||||
super.startReactApplication(reactInstanceManager, moduleName, initialProperties);
|
||||
mReactInstanceManager = reactInstanceManager;
|
||||
}
|
||||
}
|
77
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.java
generated
vendored
Normal file
77
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.java
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import androidx.core.util.Pools;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class RNGestureHandlerEvent extends Event<RNGestureHandlerEvent> {
|
||||
|
||||
public static final String EVENT_NAME = "onGestureHandlerEvent";
|
||||
|
||||
private static final int TOUCH_EVENTS_POOL_SIZE = 7; // magic
|
||||
|
||||
private static final Pools.SynchronizedPool<RNGestureHandlerEvent> EVENTS_POOL =
|
||||
new Pools.SynchronizedPool<>(TOUCH_EVENTS_POOL_SIZE);
|
||||
|
||||
public static RNGestureHandlerEvent obtain(
|
||||
GestureHandler handler,
|
||||
@Nullable RNGestureHandlerEventDataExtractor dataExtractor) {
|
||||
RNGestureHandlerEvent event = EVENTS_POOL.acquire();
|
||||
if (event == null) {
|
||||
event = new RNGestureHandlerEvent();
|
||||
}
|
||||
event.init(handler, dataExtractor);
|
||||
return event;
|
||||
}
|
||||
|
||||
private WritableMap mExtraData;
|
||||
private short mCoalescingKey;
|
||||
|
||||
private RNGestureHandlerEvent() {
|
||||
}
|
||||
|
||||
private void init(
|
||||
GestureHandler handler,
|
||||
@Nullable RNGestureHandlerEventDataExtractor dataExtractor) {
|
||||
super.init(handler.getView().getId());
|
||||
mExtraData = Arguments.createMap();
|
||||
if (dataExtractor != null) {
|
||||
dataExtractor.extractEventData(handler, mExtraData);
|
||||
}
|
||||
mExtraData.putInt("handlerTag", handler.getTag());
|
||||
mExtraData.putInt("state", handler.getState());
|
||||
mCoalescingKey = handler.getEventCoalescingKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDispose() {
|
||||
mExtraData = null;
|
||||
EVENTS_POOL.release(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventName() {
|
||||
return EVENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCoalesce() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getCoalescingKey() {
|
||||
return mCoalescingKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||
rctEventEmitter.receiveEvent(getViewTag(), EVENT_NAME, mExtraData);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
|
||||
public interface RNGestureHandlerEventDataExtractor<T extends GestureHandler> {
|
||||
void extractEventData(T handler, WritableMap eventData);
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
import com.swmansion.gesturehandler.GestureHandlerInteractionController;
|
||||
|
||||
public class RNGestureHandlerInteractionManager implements GestureHandlerInteractionController {
|
||||
|
||||
private static final String KEY_WAIT_FOR = "waitFor";
|
||||
private static final String KEY_SIMULTANEOUS_HANDLERS = "simultaneousHandlers";
|
||||
|
||||
private SparseArray<int[]> mWaitForRelations = new SparseArray<>();
|
||||
private SparseArray<int[]> mSimultaneousRelations = new SparseArray<>();
|
||||
|
||||
public void dropRelationsForHandlerWithTag(int handlerTag) {
|
||||
mWaitForRelations.remove(handlerTag);
|
||||
mSimultaneousRelations.remove(handlerTag);
|
||||
}
|
||||
|
||||
private int[] convertHandlerTagsArray(ReadableMap config, String key) {
|
||||
ReadableArray array = config.getArray(key);
|
||||
int[] result = new int[array.size()];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = array.getInt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void configureInteractions(GestureHandler handler, ReadableMap config) {
|
||||
handler.setInteractionController(this);
|
||||
if (config.hasKey(KEY_WAIT_FOR)) {
|
||||
int[] tags = convertHandlerTagsArray(config, KEY_WAIT_FOR);
|
||||
mWaitForRelations.put(handler.getTag(), tags);
|
||||
}
|
||||
if (config.hasKey(KEY_SIMULTANEOUS_HANDLERS)) {
|
||||
int[] tags = convertHandlerTagsArray(config, KEY_SIMULTANEOUS_HANDLERS);
|
||||
mSimultaneousRelations.put(handler.getTag(), tags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldWaitForHandlerFailure(GestureHandler handler, GestureHandler otherHandler) {
|
||||
int[] waitForTags = mWaitForRelations.get(handler.getTag());
|
||||
if (waitForTags != null) {
|
||||
for (int i = 0; i < waitForTags.length; i++) {
|
||||
if (waitForTags[i] == otherHandler.getTag()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRequireHandlerToWaitForFailure(GestureHandler handler,
|
||||
GestureHandler otherHandler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldHandlerBeCancelledBy(GestureHandler handler, GestureHandler otherHandler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRecognizeSimultaneously(GestureHandler handler,
|
||||
GestureHandler otherHandler) {
|
||||
int[] simultHandlerTags = mSimultaneousRelations.get(handler.getTag());
|
||||
if (simultHandlerTags != null) {
|
||||
for (int i = 0; i < simultHandlerTags.length; i++) {
|
||||
if (simultHandlerTags[i] == otherHandler.getTag()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mWaitForRelations.clear();
|
||||
mSimultaneousRelations.clear();
|
||||
}
|
||||
}
|
731
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.java
generated
vendored
Normal file
731
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.java
generated
vendored
Normal file
@ -0,0 +1,731 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.UIBlock;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.swmansion.gesturehandler.FlingGestureHandler;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
import com.swmansion.gesturehandler.LongPressGestureHandler;
|
||||
import com.swmansion.gesturehandler.NativeViewGestureHandler;
|
||||
import com.swmansion.gesturehandler.OnTouchEventListener;
|
||||
import com.swmansion.gesturehandler.PanGestureHandler;
|
||||
import com.swmansion.gesturehandler.PinchGestureHandler;
|
||||
import com.swmansion.gesturehandler.RotationGestureHandler;
|
||||
import com.swmansion.gesturehandler.TapGestureHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import static com.swmansion.gesturehandler.GestureHandler.HIT_SLOP_NONE;
|
||||
|
||||
@ReactModule(name=RNGestureHandlerModule.MODULE_NAME)
|
||||
public class RNGestureHandlerModule extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String MODULE_NAME = "RNGestureHandlerModule";
|
||||
|
||||
private static final String KEY_SHOULD_CANCEL_WHEN_OUTSIDE = "shouldCancelWhenOutside";
|
||||
private static final String KEY_ENABLED = "enabled";
|
||||
private static final String KEY_HIT_SLOP = "hitSlop";
|
||||
private static final String KEY_HIT_SLOP_LEFT = "left";
|
||||
private static final String KEY_HIT_SLOP_TOP = "top";
|
||||
private static final String KEY_HIT_SLOP_RIGHT = "right";
|
||||
private static final String KEY_HIT_SLOP_BOTTOM = "bottom";
|
||||
private static final String KEY_HIT_SLOP_VERTICAL = "vertical";
|
||||
private static final String KEY_HIT_SLOP_HORIZONTAL = "horizontal";
|
||||
private static final String KEY_HIT_SLOP_WIDTH = "width";
|
||||
private static final String KEY_HIT_SLOP_HEIGHT = "height";
|
||||
private static final String KEY_NATIVE_VIEW_SHOULD_ACTIVATE_ON_START = "shouldActivateOnStart";
|
||||
private static final String KEY_NATIVE_VIEW_DISALLOW_INTERRUPTION = "disallowInterruption";
|
||||
private static final String KEY_TAP_NUMBER_OF_TAPS = "numberOfTaps";
|
||||
private static final String KEY_TAP_MAX_DURATION_MS = "maxDurationMs";
|
||||
private static final String KEY_TAP_MAX_DELAY_MS = "maxDelayMs";
|
||||
private static final String KEY_TAP_MAX_DELTA_X = "maxDeltaX";
|
||||
private static final String KEY_TAP_MAX_DELTA_Y = "maxDeltaY";
|
||||
private static final String KEY_TAP_MAX_DIST = "maxDist";
|
||||
private static final String KEY_TAP_MIN_POINTERS = "minPointers";
|
||||
private static final String KEY_LONG_PRESS_MIN_DURATION_MS = "minDurationMs";
|
||||
private static final String KEY_LONG_PRESS_MAX_DIST = "maxDist";
|
||||
private static final String KEY_PAN_ACTIVE_OFFSET_X_START = "activeOffsetXStart";
|
||||
private static final String KEY_PAN_ACTIVE_OFFSET_X_END = "activeOffsetXEnd";
|
||||
private static final String KEY_PAN_FAIL_OFFSET_RANGE_X_START = "failOffsetXStart";
|
||||
private static final String KEY_PAN_FAIL_OFFSET_RANGE_X_END = "failOffsetXEnd";
|
||||
private static final String KEY_PAN_ACTIVE_OFFSET_Y_START = "activeOffsetYStart";
|
||||
private static final String KEY_PAN_ACTIVE_OFFSET_Y_END = "activeOffsetYEnd";
|
||||
private static final String KEY_PAN_FAIL_OFFSET_RANGE_Y_START = "failOffsetYStart";
|
||||
private static final String KEY_PAN_FAIL_OFFSET_RANGE_Y_END = "failOffsetYEnd";
|
||||
private static final String KEY_PAN_MIN_DIST = "minDist";
|
||||
private static final String KEY_PAN_MIN_VELOCITY = "minVelocity";
|
||||
private static final String KEY_PAN_MIN_VELOCITY_X = "minVelocityX";
|
||||
private static final String KEY_PAN_MIN_VELOCITY_Y = "minVelocityY";
|
||||
private static final String KEY_PAN_MIN_POINTERS = "minPointers";
|
||||
private static final String KEY_PAN_MAX_POINTERS = "maxPointers";
|
||||
private static final String KEY_PAN_AVG_TOUCHES = "avgTouches";
|
||||
private static final String KEY_NUMBER_OF_POINTERS = "numberOfPointers";
|
||||
private static final String KEY_DIRECTION= "direction";
|
||||
|
||||
private abstract static class HandlerFactory<T extends GestureHandler>
|
||||
implements RNGestureHandlerEventDataExtractor<T> {
|
||||
|
||||
public abstract Class<T> getType();
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract T create(Context context);
|
||||
|
||||
public void configure(T handler, ReadableMap config) {
|
||||
if (config.hasKey(KEY_SHOULD_CANCEL_WHEN_OUTSIDE)) {
|
||||
handler.setShouldCancelWhenOutside(config.getBoolean(KEY_SHOULD_CANCEL_WHEN_OUTSIDE));
|
||||
}
|
||||
if (config.hasKey(KEY_ENABLED)) {
|
||||
handler.setEnabled(config.getBoolean(KEY_ENABLED));
|
||||
}
|
||||
if (config.hasKey(KEY_HIT_SLOP)) {
|
||||
handleHitSlopProperty(handler, config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(T handler, WritableMap eventData) {
|
||||
eventData.putDouble("numberOfPointers", handler.getNumberOfPointers());
|
||||
}
|
||||
}
|
||||
|
||||
private static class NativeViewGestureHandlerFactory extends
|
||||
HandlerFactory<NativeViewGestureHandler> {
|
||||
@Override
|
||||
public Class<NativeViewGestureHandler> getType() {
|
||||
return NativeViewGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NativeViewGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NativeViewGestureHandler create(Context context) {
|
||||
return new NativeViewGestureHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(NativeViewGestureHandler handler, ReadableMap config) {
|
||||
super.configure(handler, config);
|
||||
if (config.hasKey(KEY_NATIVE_VIEW_SHOULD_ACTIVATE_ON_START)) {
|
||||
handler.setShouldActivateOnStart(
|
||||
config.getBoolean(KEY_NATIVE_VIEW_SHOULD_ACTIVATE_ON_START));
|
||||
}
|
||||
if (config.hasKey(KEY_NATIVE_VIEW_DISALLOW_INTERRUPTION)) {
|
||||
handler.setDisallowInterruption(config.getBoolean(KEY_NATIVE_VIEW_DISALLOW_INTERRUPTION));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(NativeViewGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putBoolean("pointerInside", handler.isWithinBounds());
|
||||
}
|
||||
}
|
||||
|
||||
private static class TapGestureHandlerFactory extends HandlerFactory<TapGestureHandler> {
|
||||
@Override
|
||||
public Class<TapGestureHandler> getType() {
|
||||
return TapGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TapGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TapGestureHandler create(Context context) {
|
||||
return new TapGestureHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(TapGestureHandler handler, ReadableMap config) {
|
||||
super.configure(handler, config);
|
||||
if (config.hasKey(KEY_TAP_NUMBER_OF_TAPS)) {
|
||||
handler.setNumberOfTaps(config.getInt(KEY_TAP_NUMBER_OF_TAPS));
|
||||
}
|
||||
if (config.hasKey(KEY_TAP_MAX_DURATION_MS)) {
|
||||
handler.setMaxDurationMs(config.getInt(KEY_TAP_MAX_DURATION_MS));
|
||||
}
|
||||
if (config.hasKey(KEY_TAP_MAX_DELAY_MS)) {
|
||||
handler.setMaxDelayMs(config.getInt(KEY_TAP_MAX_DELAY_MS));
|
||||
}
|
||||
if (config.hasKey(KEY_TAP_MAX_DELTA_X)) {
|
||||
handler.setMaxDx(PixelUtil.toPixelFromDIP(config.getDouble(KEY_TAP_MAX_DELTA_X)));
|
||||
}
|
||||
if (config.hasKey(KEY_TAP_MAX_DELTA_Y)) {
|
||||
handler.setMaxDy(PixelUtil.toPixelFromDIP(config.getDouble(KEY_TAP_MAX_DELTA_Y)));
|
||||
}
|
||||
if (config.hasKey(KEY_TAP_MAX_DIST)) {
|
||||
handler.setMaxDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_TAP_MAX_DIST)));
|
||||
}
|
||||
if (config.hasKey(KEY_TAP_MIN_POINTERS)) {
|
||||
handler.setMinNumberOfPointers(config.getInt(KEY_TAP_MIN_POINTERS));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(TapGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putDouble("x", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionX()));
|
||||
eventData.putDouble("y", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionY()));
|
||||
eventData.putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionX()));
|
||||
eventData.putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionY()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class LongPressGestureHandlerFactory extends
|
||||
HandlerFactory<LongPressGestureHandler> {
|
||||
@Override
|
||||
public Class<LongPressGestureHandler> getType() {
|
||||
return LongPressGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LongPressGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongPressGestureHandler create(Context context) {
|
||||
return new LongPressGestureHandler(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(LongPressGestureHandler handler, ReadableMap config) {
|
||||
super.configure(handler, config);
|
||||
if (config.hasKey(KEY_LONG_PRESS_MIN_DURATION_MS)) {
|
||||
handler.setMinDurationMs(config.getInt(KEY_LONG_PRESS_MIN_DURATION_MS));
|
||||
}
|
||||
if (config.hasKey(KEY_LONG_PRESS_MAX_DIST)) {
|
||||
handler.setMaxDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_LONG_PRESS_MAX_DIST)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(LongPressGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putDouble("x", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionX()));
|
||||
eventData.putDouble("y", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionY()));
|
||||
eventData.putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionX()));
|
||||
eventData.putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionY()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class PanGestureHandlerFactory extends HandlerFactory<PanGestureHandler> {
|
||||
@Override
|
||||
public Class<PanGestureHandler> getType() {
|
||||
return PanGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PanGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PanGestureHandler create(Context context) {
|
||||
return new PanGestureHandler(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(PanGestureHandler handler, ReadableMap config) {
|
||||
super.configure(handler, config);
|
||||
boolean hasCustomActivationCriteria = false;
|
||||
if(config.hasKey(KEY_PAN_ACTIVE_OFFSET_X_START)) {
|
||||
handler.setActiveOffsetXStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_X_START)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_ACTIVE_OFFSET_X_END)) {
|
||||
handler.setActiveOffsetXEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_X_END)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_X_START)) {
|
||||
handler.setFailOffsetXStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_X_START)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_X_END)) {
|
||||
handler.setFailOffsetXEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_X_END)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_ACTIVE_OFFSET_Y_START)) {
|
||||
handler.setActiveOffsetYStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_Y_START)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_ACTIVE_OFFSET_Y_END)) {
|
||||
handler.setActiveOffsetYEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_Y_END)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_Y_START)) {
|
||||
handler.setFailOffsetYStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_Y_START)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if(config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_Y_END)) {
|
||||
handler.setFailOffsetYEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_Y_END)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
|
||||
if (config.hasKey(KEY_PAN_MIN_VELOCITY)) {
|
||||
// This value is actually in DPs/ms, but we can use the same function as for converting
|
||||
// from DPs to pixels as the unit we're converting is in the numerator
|
||||
handler.setMinVelocity(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_VELOCITY)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if (config.hasKey(KEY_PAN_MIN_VELOCITY_X)) {
|
||||
handler.setMinVelocityX(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_VELOCITY_X)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
if (config.hasKey(KEY_PAN_MIN_VELOCITY_Y)) {
|
||||
handler.setMinVelocityY(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_VELOCITY_Y)));
|
||||
hasCustomActivationCriteria = true;
|
||||
}
|
||||
|
||||
// PanGestureHandler sets minDist by default, if there are custom criteria specified we want
|
||||
// to reset that setting and use provided criteria instead.
|
||||
if (config.hasKey(KEY_PAN_MIN_DIST)) {
|
||||
handler.setMinDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_DIST)));
|
||||
} else if (hasCustomActivationCriteria) {
|
||||
handler.setMinDist(Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
if (config.hasKey(KEY_PAN_MIN_POINTERS)) {
|
||||
handler.setMinPointers(config.getInt(KEY_PAN_MIN_POINTERS));
|
||||
}
|
||||
if (config.hasKey(KEY_PAN_MAX_POINTERS)) {
|
||||
handler.setMaxPointers(config.getInt(KEY_PAN_MAX_POINTERS));
|
||||
}
|
||||
if (config.hasKey(KEY_PAN_AVG_TOUCHES)) {
|
||||
handler.setAverageTouches(config.getBoolean(KEY_PAN_AVG_TOUCHES));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(PanGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putDouble("x", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionX()));
|
||||
eventData.putDouble("y", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionY()));
|
||||
eventData.putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionX()));
|
||||
eventData.putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionY()));
|
||||
eventData.putDouble("translationX", PixelUtil.toDIPFromPixel(handler.getTranslationX()));
|
||||
eventData.putDouble("translationY", PixelUtil.toDIPFromPixel(handler.getTranslationY()));
|
||||
eventData.putDouble("velocityX", PixelUtil.toDIPFromPixel(handler.getVelocityX()));
|
||||
eventData.putDouble("velocityY", PixelUtil.toDIPFromPixel(handler.getVelocityY()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class PinchGestureHandlerFactory extends HandlerFactory<PinchGestureHandler> {
|
||||
@Override
|
||||
public Class<PinchGestureHandler> getType() {
|
||||
return PinchGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PinchGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PinchGestureHandler create(Context context) {
|
||||
return new PinchGestureHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(PinchGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putDouble("scale", handler.getScale());
|
||||
eventData.putDouble("focalX", PixelUtil.toDIPFromPixel(handler.getFocalPointX()));
|
||||
eventData.putDouble("focalY", PixelUtil.toDIPFromPixel(handler.getFocalPointY()));
|
||||
eventData.putDouble("velocity", handler.getVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
private static class FlingGestureHandlerFactory extends HandlerFactory<FlingGestureHandler> {
|
||||
@Override
|
||||
public Class<FlingGestureHandler> getType() {
|
||||
return FlingGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FlingGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlingGestureHandler create(Context context) {
|
||||
return new FlingGestureHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(FlingGestureHandler handler, ReadableMap config) {
|
||||
super.configure(handler, config);
|
||||
if (config.hasKey(KEY_NUMBER_OF_POINTERS)) {
|
||||
handler.setNumberOfPointersRequired(config.getInt(KEY_NUMBER_OF_POINTERS));
|
||||
}
|
||||
if (config.hasKey(KEY_DIRECTION)) {
|
||||
handler.setDirection(config.getInt(KEY_DIRECTION));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void extractEventData(FlingGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putDouble("x", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionX()));
|
||||
eventData.putDouble("y", PixelUtil.toDIPFromPixel(handler.getLastRelativePositionY()));
|
||||
eventData.putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionX()));
|
||||
eventData.putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.getLastAbsolutePositionY()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RotationGestureHandlerFactory extends HandlerFactory<RotationGestureHandler> {
|
||||
@Override
|
||||
public Class<RotationGestureHandler> getType() {
|
||||
return RotationGestureHandler.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RotationGestureHandler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RotationGestureHandler create(Context context) {
|
||||
return new RotationGestureHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractEventData(RotationGestureHandler handler, WritableMap eventData) {
|
||||
super.extractEventData(handler, eventData);
|
||||
eventData.putDouble("rotation", handler.getRotation());
|
||||
eventData.putDouble("anchorX", PixelUtil.toDIPFromPixel(handler.getAnchorX()));
|
||||
eventData.putDouble("anchorY", PixelUtil.toDIPFromPixel(handler.getAnchorY()));
|
||||
eventData.putDouble("velocity", handler.getVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
private OnTouchEventListener mEventListener = new OnTouchEventListener() {
|
||||
@Override
|
||||
public void onTouchEvent(GestureHandler handler, MotionEvent event) {
|
||||
RNGestureHandlerModule.this.onTouchEvent(handler, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChange(GestureHandler handler, int newState, int oldState) {
|
||||
RNGestureHandlerModule.this.onStateChange(handler, newState, oldState);
|
||||
}
|
||||
};
|
||||
|
||||
private HandlerFactory[] mHandlerFactories = new HandlerFactory[] {
|
||||
new NativeViewGestureHandlerFactory(),
|
||||
new TapGestureHandlerFactory(),
|
||||
new LongPressGestureHandlerFactory(),
|
||||
new PanGestureHandlerFactory(),
|
||||
new PinchGestureHandlerFactory(),
|
||||
new RotationGestureHandlerFactory(),
|
||||
new FlingGestureHandlerFactory()
|
||||
};
|
||||
private final RNGestureHandlerRegistry mRegistry = new RNGestureHandlerRegistry();
|
||||
|
||||
private RNGestureHandlerInteractionManager mInteractionManager =
|
||||
new RNGestureHandlerInteractionManager();
|
||||
private List<RNGestureHandlerRootHelper> mRoots = new ArrayList<>();
|
||||
private List<Integer> mEnqueuedRootViewInit = new ArrayList<>();
|
||||
|
||||
public RNGestureHandlerModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createGestureHandler(
|
||||
String handlerName,
|
||||
int handlerTag,
|
||||
ReadableMap config) {
|
||||
for (int i = 0; i < mHandlerFactories.length; i++) {
|
||||
HandlerFactory handlerFactory = mHandlerFactories[i];
|
||||
if (handlerFactory.getName().equals(handlerName)) {
|
||||
GestureHandler handler = handlerFactory.create(getReactApplicationContext());
|
||||
handler.setTag(handlerTag);
|
||||
handler.setOnTouchEventListener(mEventListener);
|
||||
mRegistry.registerHandler(handler);
|
||||
mInteractionManager.configureInteractions(handler, config);
|
||||
handlerFactory.configure(handler, config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new JSApplicationIllegalArgumentException("Invalid handler name " + handlerName);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void attachGestureHandler(int handlerTag, int viewTag) {
|
||||
tryInitializeHandlerForReactRootView(viewTag);
|
||||
if (!mRegistry.attachHandlerToView(handlerTag, viewTag)) {
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"Handler with tag " + handlerTag + " does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void updateGestureHandler(
|
||||
int handlerTag,
|
||||
ReadableMap config) {
|
||||
GestureHandler handler = mRegistry.getHandler(handlerTag);
|
||||
if (handler != null) {
|
||||
HandlerFactory factory = findFactoryForHandler(handler);
|
||||
if (factory != null) {
|
||||
mInteractionManager.dropRelationsForHandlerWithTag(handlerTag);
|
||||
mInteractionManager.configureInteractions(handler, config);
|
||||
factory.configure(handler, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void dropGestureHandler(int handlerTag) {
|
||||
mInteractionManager.dropRelationsForHandlerWithTag(handlerTag);
|
||||
mRegistry.dropHandler(handlerTag);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void handleSetJSResponder(int viewTag, boolean blockNativeResponder) {
|
||||
if (mRegistry != null) {
|
||||
RNGestureHandlerRootHelper rootView = findRootHelperForViewAncestor(viewTag);
|
||||
if (rootView != null) {
|
||||
rootView.handleSetJSResponder(viewTag, blockNativeResponder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void handleClearJSResponder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Map getConstants() {
|
||||
return MapBuilder.of("State", MapBuilder.of(
|
||||
"UNDETERMINED", GestureHandler.STATE_UNDETERMINED,
|
||||
"BEGAN", GestureHandler.STATE_BEGAN,
|
||||
"ACTIVE", GestureHandler.STATE_ACTIVE,
|
||||
"CANCELLED", GestureHandler.STATE_CANCELLED,
|
||||
"FAILED", GestureHandler.STATE_FAILED,
|
||||
"END", GestureHandler.STATE_END
|
||||
), "Direction", MapBuilder.of(
|
||||
"RIGHT", GestureHandler.DIRECTION_RIGHT,
|
||||
"LEFT", GestureHandler.DIRECTION_LEFT,
|
||||
"UP", GestureHandler.DIRECTION_UP,
|
||||
"DOWN", GestureHandler.DIRECTION_DOWN
|
||||
));
|
||||
}
|
||||
|
||||
public RNGestureHandlerRegistry getRegistry() {
|
||||
return mRegistry;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCatalystInstanceDestroy() {
|
||||
mRegistry.dropAllHandlers();
|
||||
mInteractionManager.reset();
|
||||
synchronized (mRoots) {
|
||||
while (!mRoots.isEmpty()) {
|
||||
int sizeBefore = mRoots.size();
|
||||
RNGestureHandlerRootHelper root = mRoots.get(0);
|
||||
ViewGroup reactRootView = root.getRootView();
|
||||
if (reactRootView instanceof RNGestureHandlerEnabledRootView) {
|
||||
((RNGestureHandlerEnabledRootView) reactRootView).tearDown();
|
||||
} else {
|
||||
root.tearDown();
|
||||
}
|
||||
if (mRoots.size() >= sizeBefore) {
|
||||
throw new IllegalStateException("Expected root helper to get unregistered while tearing down");
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onCatalystInstanceDestroy();
|
||||
}
|
||||
|
||||
private void tryInitializeHandlerForReactRootView(int ancestorViewTag) {
|
||||
UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
|
||||
final int rootViewTag = uiManager.resolveRootTagFromReactTag(ancestorViewTag);
|
||||
if (rootViewTag < 1) {
|
||||
throw new JSApplicationIllegalArgumentException("Could find root view for a given ancestor with tag "
|
||||
+ ancestorViewTag);
|
||||
}
|
||||
synchronized (mRoots) {
|
||||
for (int i = 0; i < mRoots.size(); i++) {
|
||||
RNGestureHandlerRootHelper root = mRoots.get(i);
|
||||
ViewGroup rootView = root.getRootView();
|
||||
if (rootView instanceof ReactRootView && ((ReactRootView) rootView).getRootViewTag() == rootViewTag) {
|
||||
// we have found root helper registered for a given react root, we don't need to
|
||||
// initialize a new one then
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized (mEnqueuedRootViewInit) {
|
||||
if (mEnqueuedRootViewInit.contains(rootViewTag)) {
|
||||
// root view initialization already enqueued -> we skip
|
||||
return;
|
||||
}
|
||||
mEnqueuedRootViewInit.add(rootViewTag);
|
||||
}
|
||||
// root helper for a given root tag has not been found, we may wat to check if the root view is
|
||||
// an instance of RNGestureHandlerEnabledRootView and then initialize gesture handler with it
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
View view = nativeViewHierarchyManager.resolveView(rootViewTag);
|
||||
if (view instanceof RNGestureHandlerEnabledRootView) {
|
||||
((RNGestureHandlerEnabledRootView) view).initialize();
|
||||
} else {
|
||||
// Seems like the root view is something else than RNGestureHandlerEnabledRootView, this
|
||||
// is fine though as long as gestureHandlerRootHOC is used in JS
|
||||
// FIXME: check and warn about gestureHandlerRootHOC
|
||||
}
|
||||
synchronized (mEnqueuedRootViewInit) {
|
||||
mEnqueuedRootViewInit.remove(new Integer(rootViewTag));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerRootHelper(RNGestureHandlerRootHelper root) {
|
||||
synchronized (mRoots) {
|
||||
if (mRoots.contains(root)) {
|
||||
throw new IllegalStateException("Root helper" + root + " already registered");
|
||||
}
|
||||
mRoots.add(root);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterRootHelper(RNGestureHandlerRootHelper root) {
|
||||
synchronized (mRoots) {
|
||||
mRoots.remove(root);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private @Nullable RNGestureHandlerRootHelper findRootHelperForViewAncestor(int viewTag) {
|
||||
UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
|
||||
int rootViewTag = uiManager.resolveRootTagFromReactTag(viewTag);
|
||||
if (rootViewTag < 1) {
|
||||
return null;
|
||||
}
|
||||
synchronized (mRoots) {
|
||||
for (int i = 0; i < mRoots.size(); i++) {
|
||||
RNGestureHandlerRootHelper root = mRoots.get(i);
|
||||
ViewGroup rootView = root.getRootView();
|
||||
if (rootView instanceof ReactRootView && ((ReactRootView) rootView).getRootViewTag() == rootViewTag) {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable HandlerFactory findFactoryForHandler(GestureHandler handler) {
|
||||
for (int i = 0; i < mHandlerFactories.length; i++) {
|
||||
HandlerFactory factory = mHandlerFactories[i];
|
||||
if (factory.getType().equals(handler.getClass())) {
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void onTouchEvent(GestureHandler handler, MotionEvent motionEvent) {
|
||||
if (handler.getTag() < 0) {
|
||||
// root containers use negative tags, we don't need to dispatch events for them to the JS
|
||||
return;
|
||||
}
|
||||
if (handler.getState() == GestureHandler.STATE_ACTIVE) {
|
||||
HandlerFactory handlerFactory = findFactoryForHandler(handler);
|
||||
EventDispatcher eventDispatcher = getReactApplicationContext()
|
||||
.getNativeModule(UIManagerModule.class)
|
||||
.getEventDispatcher();
|
||||
RNGestureHandlerEvent event = RNGestureHandlerEvent.obtain(handler, handlerFactory);
|
||||
eventDispatcher.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
private void onStateChange(GestureHandler handler, int newState, int oldState) {
|
||||
if (handler.getTag() < 0) {
|
||||
// root containers use negative tags, we don't need to dispatch events for them to the JS
|
||||
return;
|
||||
}
|
||||
HandlerFactory handlerFactory = findFactoryForHandler(handler);
|
||||
EventDispatcher eventDispatcher = getReactApplicationContext()
|
||||
.getNativeModule(UIManagerModule.class)
|
||||
.getEventDispatcher();
|
||||
RNGestureHandlerStateChangeEvent event = RNGestureHandlerStateChangeEvent.obtain(
|
||||
handler,
|
||||
newState,
|
||||
oldState,
|
||||
handlerFactory);
|
||||
eventDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
private static void handleHitSlopProperty(GestureHandler handler, ReadableMap config) {
|
||||
if (config.getType(KEY_HIT_SLOP) == ReadableType.Number) {
|
||||
float hitSlop = PixelUtil.toPixelFromDIP(config.getDouble(KEY_HIT_SLOP));
|
||||
handler.setHitSlop(hitSlop, hitSlop, hitSlop, hitSlop, HIT_SLOP_NONE, HIT_SLOP_NONE);
|
||||
} else {
|
||||
ReadableMap hitSlop = config.getMap(KEY_HIT_SLOP);
|
||||
float left = HIT_SLOP_NONE, top = HIT_SLOP_NONE, right = HIT_SLOP_NONE, bottom = HIT_SLOP_NONE;
|
||||
float width = HIT_SLOP_NONE, height = HIT_SLOP_NONE;
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_HORIZONTAL)) {
|
||||
float horizontalPad = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_HORIZONTAL));
|
||||
left = right = horizontalPad;
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_VERTICAL)) {
|
||||
float verticalPad = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_VERTICAL));
|
||||
top = bottom = verticalPad;
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_LEFT)) {
|
||||
left = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_LEFT));
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_TOP)) {
|
||||
top = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_TOP));
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_RIGHT)) {
|
||||
right = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_RIGHT));
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_BOTTOM)) {
|
||||
bottom = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_BOTTOM));
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_WIDTH)) {
|
||||
width = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_WIDTH));
|
||||
}
|
||||
if (hitSlop.hasKey(KEY_HIT_SLOP_HEIGHT)) {
|
||||
height = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_HEIGHT));
|
||||
}
|
||||
handler.setHitSlop(left, top, right, bottom, width, height);
|
||||
}
|
||||
}
|
||||
}
|
31
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerPackage.java
generated
vendored
Normal file
31
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerPackage.java
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.react.views.view.ReactViewManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class RNGestureHandlerPackage implements ReactPackage {
|
||||
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
return Arrays.<NativeModule>asList(new RNGestureHandlerModule(reactContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Arrays.<ViewManager>asList(
|
||||
new RNGestureHandlerRootViewManager(),
|
||||
new RNGestureHandlerButtonViewManager());
|
||||
}
|
||||
}
|
101
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.java
generated
vendored
Normal file
101
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.java
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
import com.swmansion.gesturehandler.GestureHandlerRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class RNGestureHandlerRegistry implements GestureHandlerRegistry {
|
||||
|
||||
private final SparseArray<GestureHandler> mHandlers = new SparseArray<>();
|
||||
private final SparseArray<Integer> mAttachedTo = new SparseArray<>();
|
||||
private final SparseArray<ArrayList<GestureHandler>> mHandlersForView = new SparseArray<>();
|
||||
|
||||
public synchronized void registerHandler(GestureHandler handler) {
|
||||
mHandlers.put(handler.getTag(), handler);
|
||||
}
|
||||
|
||||
public synchronized @Nullable GestureHandler getHandler(int handlerTag) {
|
||||
return mHandlers.get(handlerTag);
|
||||
}
|
||||
|
||||
public synchronized boolean attachHandlerToView(int handlerTag, int viewTag) {
|
||||
GestureHandler handler = mHandlers.get(handlerTag);
|
||||
if (handler != null) {
|
||||
detachHandler(handler);
|
||||
registerHandlerForViewWithTag(viewTag, handler);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void registerHandlerForViewWithTag(int viewTag, GestureHandler handler) {
|
||||
if (mAttachedTo.get(handler.getTag()) != null) {
|
||||
throw new IllegalStateException("Handler " + handler + " already attached");
|
||||
}
|
||||
mAttachedTo.put(handler.getTag(), viewTag);
|
||||
ArrayList<GestureHandler> listToAdd = mHandlersForView.get(viewTag);
|
||||
if (listToAdd == null) {
|
||||
listToAdd = new ArrayList<>(1);
|
||||
listToAdd.add(handler);
|
||||
mHandlersForView.put(viewTag, listToAdd);
|
||||
} else {
|
||||
listToAdd.add(handler);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void detachHandler(final GestureHandler handler) {
|
||||
Integer attachedToView = mAttachedTo.get(handler.getTag());
|
||||
if (attachedToView != null) {
|
||||
mAttachedTo.remove(handler.getTag());
|
||||
ArrayList<GestureHandler> attachedHandlers = mHandlersForView.get(attachedToView);
|
||||
if (attachedHandlers != null) {
|
||||
attachedHandlers.remove(handler);
|
||||
if (attachedHandlers.size() == 0) {
|
||||
mHandlersForView.remove(attachedToView);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (handler.getView() != null) {
|
||||
// Handler is in "prepared" state which means it is registered in the orchestrator and can
|
||||
// receive touch events. This means that before we remove it from the registry we need to
|
||||
// "cancel" it so that orchestrator does no longer keep a reference to it.
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handler.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void dropHandler(int handlerTag) {
|
||||
GestureHandler handler = mHandlers.get(handlerTag);
|
||||
if (handler != null) {
|
||||
detachHandler(handler);
|
||||
mHandlers.remove(handlerTag);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void dropAllHandlers() {
|
||||
mHandlers.clear();
|
||||
mAttachedTo.clear();
|
||||
mHandlersForView.clear();
|
||||
}
|
||||
|
||||
public synchronized ArrayList<GestureHandler> getHandlersForViewWithTag(int viewTag) {
|
||||
return mHandlersForView.get(viewTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ArrayList<GestureHandler> getHandlersForView(View view) {
|
||||
return getHandlersForViewWithTag(view.getId());
|
||||
}
|
||||
}
|
151
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.java
generated
vendored
Normal file
151
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.java
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.views.modal.RNGHModalUtils;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
import com.swmansion.gesturehandler.GestureHandlerOrchestrator;
|
||||
|
||||
public class RNGestureHandlerRootHelper {
|
||||
|
||||
private static final float MIN_ALPHA_FOR_TOUCH = 0.1f;
|
||||
|
||||
private final ReactContext mContext;
|
||||
private final GestureHandlerOrchestrator mOrchestrator;
|
||||
private final GestureHandler mJSGestureHandler;
|
||||
private final ViewGroup mRootView;
|
||||
|
||||
private boolean mShouldIntercept = false;
|
||||
private boolean mPassingTouch = false;
|
||||
|
||||
private static ViewGroup findRootViewTag(ViewGroup viewGroup) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
ViewParent parent = viewGroup;
|
||||
while (parent != null && !(parent instanceof ReactRootView || RNGHModalUtils.isDialogRootViewGroup(parent))) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (parent == null) {
|
||||
throw new IllegalStateException("View " + viewGroup + " has not been mounted under" +
|
||||
" ReactRootView");
|
||||
}
|
||||
return (ViewGroup) parent;
|
||||
}
|
||||
|
||||
public RNGestureHandlerRootHelper(ReactContext context, ViewGroup wrappedView) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
int wrappedViewTag = wrappedView.getId();
|
||||
if (wrappedViewTag < 1) {
|
||||
throw new IllegalStateException("Expect view tag to be set for " + wrappedView);
|
||||
}
|
||||
|
||||
RNGestureHandlerModule module = context.getNativeModule(RNGestureHandlerModule.class);
|
||||
RNGestureHandlerRegistry registry = module.getRegistry();
|
||||
|
||||
mRootView = findRootViewTag(wrappedView);
|
||||
|
||||
Log.i(
|
||||
ReactConstants.TAG,
|
||||
"[GESTURE HANDLER] Initialize gesture handler for root view " + mRootView);
|
||||
|
||||
mContext = context;
|
||||
mOrchestrator = new GestureHandlerOrchestrator(
|
||||
wrappedView, registry, new RNViewConfigurationHelper());
|
||||
mOrchestrator.setMinimumAlphaForTraversal(MIN_ALPHA_FOR_TOUCH);
|
||||
|
||||
mJSGestureHandler = new RootViewGestureHandler();
|
||||
mJSGestureHandler.setTag(-wrappedViewTag);
|
||||
registry.registerHandler(mJSGestureHandler);
|
||||
registry.attachHandlerToView(mJSGestureHandler.getTag(), wrappedViewTag);
|
||||
|
||||
module.registerRootHelper(this);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
Log.i(
|
||||
ReactConstants.TAG,
|
||||
"[GESTURE HANDLER] Tearing down gesture handler registered for root view " + mRootView);
|
||||
RNGestureHandlerModule module = mContext.getNativeModule(RNGestureHandlerModule.class);
|
||||
module.getRegistry().dropHandler(mJSGestureHandler.getTag());
|
||||
module.unregisterRootHelper(this);
|
||||
}
|
||||
|
||||
public ViewGroup getRootView() {
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
private class RootViewGestureHandler extends GestureHandler {
|
||||
@Override
|
||||
protected void onHandle(MotionEvent event) {
|
||||
int currentState = getState();
|
||||
if (currentState == STATE_UNDETERMINED) {
|
||||
begin();
|
||||
mShouldIntercept = false;
|
||||
}
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancel() {
|
||||
mShouldIntercept = true;
|
||||
long time = SystemClock.uptimeMillis();
|
||||
MotionEvent event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
event.setAction(MotionEvent.ACTION_CANCEL);
|
||||
if (mRootView instanceof ReactRootView) {
|
||||
((ReactRootView) mRootView).onChildStartedNativeGesture(event);
|
||||
} else {
|
||||
RNGHModalUtils.dialogRootViewGroupOnChildStartedNativeGesture(mRootView, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
// If this method gets called it means that some native view is attempting to grab lock for
|
||||
// touch event delivery. In that case we cancel all gesture recognizers
|
||||
if (mOrchestrator != null && !mPassingTouch) {
|
||||
// if we are in the process of delivering touch events via GH orchestrator, we don't want to
|
||||
// treat it as a native gesture capturing the lock
|
||||
tryCancelAllHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
// We mark `mPassingTouch` before we get into `mOrchestrator.onTouchEvent` so that we can tell
|
||||
// if `requestDisallow` has been called as a result of a normal gesture handling process or
|
||||
// as a result of one of the gesture handlers activating
|
||||
mPassingTouch = true;
|
||||
mOrchestrator.onTouchEvent(ev);
|
||||
mPassingTouch = false;
|
||||
|
||||
return mShouldIntercept;
|
||||
}
|
||||
|
||||
private void tryCancelAllHandlers() {
|
||||
// In order to cancel handlers we activate handler that is hooked to the root view
|
||||
if (mJSGestureHandler != null && mJSGestureHandler.getState() == GestureHandler.STATE_BEGAN) {
|
||||
// Try activate main JS handler
|
||||
mJSGestureHandler.activate();
|
||||
mJSGestureHandler.end();
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void handleSetJSResponder(final int viewTag, final boolean blockNativeResponder) {
|
||||
if (blockNativeResponder) {
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tryCancelAllHandlers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public interface RNGestureHandlerRootInterface {
|
||||
@Nullable RNGestureHandlerRootHelper getRootHelper();
|
||||
}
|
76
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.java
generated
vendored
Normal file
76
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.java
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.util.Log;
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class RNGestureHandlerRootView extends ReactViewGroup {
|
||||
|
||||
private static boolean hasGestureHandlerEnabledRootView(ViewGroup viewGroup) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
ViewParent parent = viewGroup.getParent();
|
||||
while (parent != null) {
|
||||
if (parent instanceof RNGestureHandlerEnabledRootView || parent instanceof RNGestureHandlerRootView) {
|
||||
return true;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean mEnabled;
|
||||
private @Nullable RNGestureHandlerRootHelper mRootHelper;
|
||||
|
||||
public RNGestureHandlerRootView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
mEnabled = !hasGestureHandlerEnabledRootView(this);
|
||||
|
||||
if (!mEnabled) {
|
||||
Log.i(
|
||||
ReactConstants.TAG,
|
||||
"[GESTURE HANDLER] Gesture handler is already enabled for a parent view");
|
||||
}
|
||||
|
||||
if (mEnabled && mRootHelper == null) {
|
||||
mRootHelper = new RNGestureHandlerRootHelper((ReactContext) getContext(), this);
|
||||
}
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
if (mRootHelper != null) {
|
||||
mRootHelper.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (mEnabled && Assertions.assertNotNull(mRootHelper).dispatchTouchEvent(ev)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
if (mEnabled) {
|
||||
Assertions.assertNotNull(mRootHelper).requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
super.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
}
|
49
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.java
generated
vendored
Normal file
49
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.java
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* React native's view manager used for creating instances of {@link }RNGestureHandlerRootView}. It
|
||||
* is being used by projects using react-native-navigation where for each screen new root view need
|
||||
* to be provided.
|
||||
*/
|
||||
@ReactModule(name = RNGestureHandlerRootViewManager.REACT_CLASS)
|
||||
public class RNGestureHandlerRootViewManager extends ViewGroupManager<RNGestureHandlerRootView> {
|
||||
|
||||
public static final String REACT_CLASS = "GestureHandlerRootView";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RNGestureHandlerRootView createViewInstance(ThemedReactContext reactContext) {
|
||||
return new RNGestureHandlerRootView(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropViewInstance(RNGestureHandlerRootView view) {
|
||||
view.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The following event configuration is necessary even if you are not using
|
||||
* GestureHandlerRootView component directly.
|
||||
*/
|
||||
@Override
|
||||
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
|
||||
return MapBuilder.of(
|
||||
RNGestureHandlerEvent.EVENT_NAME,
|
||||
MapBuilder.of("registrationName", RNGestureHandlerEvent.EVENT_NAME),
|
||||
RNGestureHandlerStateChangeEvent.EVENT_NAME,
|
||||
MapBuilder.of("registrationName", RNGestureHandlerStateChangeEvent.EVENT_NAME));
|
||||
}
|
||||
}
|
82
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.java
generated
vendored
Normal file
82
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.java
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import androidx.core.util.Pools;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.swmansion.gesturehandler.GestureHandler;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class RNGestureHandlerStateChangeEvent extends Event<RNGestureHandlerStateChangeEvent>{
|
||||
|
||||
public static final String EVENT_NAME = "onGestureHandlerStateChange";
|
||||
|
||||
private static final int TOUCH_EVENTS_POOL_SIZE = 7; // magic
|
||||
|
||||
private static final Pools.SynchronizedPool<RNGestureHandlerStateChangeEvent> EVENTS_POOL =
|
||||
new Pools.SynchronizedPool<>(TOUCH_EVENTS_POOL_SIZE);
|
||||
|
||||
public static RNGestureHandlerStateChangeEvent obtain(
|
||||
GestureHandler handler,
|
||||
int newState,
|
||||
int oldState,
|
||||
@Nullable RNGestureHandlerEventDataExtractor dataExtractor) {
|
||||
RNGestureHandlerStateChangeEvent event = EVENTS_POOL.acquire();
|
||||
if (event == null) {
|
||||
event = new RNGestureHandlerStateChangeEvent();
|
||||
}
|
||||
event.init(handler, newState, oldState, dataExtractor);
|
||||
return event;
|
||||
}
|
||||
|
||||
private WritableMap mExtraData;
|
||||
|
||||
private RNGestureHandlerStateChangeEvent() {
|
||||
}
|
||||
|
||||
private void init(
|
||||
GestureHandler handler,
|
||||
int newState,
|
||||
int oldState,
|
||||
@Nullable RNGestureHandlerEventDataExtractor dataExtractor) {
|
||||
super.init(handler.getView().getId());
|
||||
mExtraData = Arguments.createMap();
|
||||
if (dataExtractor != null) {
|
||||
dataExtractor.extractEventData(handler, mExtraData);
|
||||
}
|
||||
mExtraData.putInt("handlerTag", handler.getTag());
|
||||
mExtraData.putInt("state", newState);
|
||||
mExtraData.putInt("oldState", oldState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDispose() {
|
||||
mExtraData = null;
|
||||
EVENTS_POOL.release(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventName() {
|
||||
return EVENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCoalesce() {
|
||||
// TODO: coalescing
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getCoalescingKey() {
|
||||
// TODO: coalescing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||
rctEventEmitter.receiveEvent(getViewTag(), EVENT_NAME, mExtraData);
|
||||
}
|
||||
}
|
61
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNViewConfigurationHelper.java
generated
vendored
Normal file
61
node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNViewConfigurationHelper.java
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
package com.swmansion.gesturehandler.react;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.uimanager.PointerEvents;
|
||||
import com.facebook.react.uimanager.ReactPointerEventsView;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
import com.swmansion.gesturehandler.PointerEventsConfig;
|
||||
import com.swmansion.gesturehandler.ViewConfigurationHelper;
|
||||
|
||||
public class RNViewConfigurationHelper implements ViewConfigurationHelper {
|
||||
|
||||
@Override
|
||||
public PointerEventsConfig getPointerEventsConfigForView(View view) {
|
||||
PointerEvents pointerEvents;
|
||||
pointerEvents = view instanceof ReactPointerEventsView ?
|
||||
((ReactPointerEventsView) view).getPointerEvents() :
|
||||
PointerEvents.AUTO;
|
||||
|
||||
// Views that are disabled should never be the target of pointer events. However, their children
|
||||
// can be because some views (SwipeRefreshLayout) use enabled but still have children that can
|
||||
// be valid targets.
|
||||
if (!view.isEnabled()) {
|
||||
if (pointerEvents == PointerEvents.AUTO) {
|
||||
return PointerEventsConfig.BOX_NONE;
|
||||
} else if (pointerEvents == PointerEvents.BOX_ONLY) {
|
||||
return PointerEventsConfig.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (pointerEvents) {
|
||||
case BOX_ONLY: return PointerEventsConfig.BOX_ONLY;
|
||||
case BOX_NONE: return PointerEventsConfig.BOX_NONE;
|
||||
case NONE: return PointerEventsConfig.NONE;
|
||||
}
|
||||
|
||||
return PointerEventsConfig.AUTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildInDrawingOrderAtIndex(ViewGroup parent, int index) {
|
||||
if (parent instanceof ReactViewGroup) {
|
||||
return parent.getChildAt(((ReactViewGroup) parent).getZIndexMappedChildIndex(index));
|
||||
}
|
||||
return parent.getChildAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewClippingChildren(ViewGroup view) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && !view.getClipChildren()) {
|
||||
if (view instanceof ReactViewGroup) {
|
||||
String overflow = ((ReactViewGroup) view).getOverflow();
|
||||
return "hidden".equals(overflow);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user