Skip to content

Commit f895fbb

Browse files
committed
fix: new option shouldStartGesture
allow you to force a gesture to not start from JS
1 parent e365a70 commit f895fbb

File tree

14 files changed

+108
-150
lines changed

14 files changed

+108
-150
lines changed

plugin/platforms/android/java/com/swmansion/gesturehandler/GestureHandler.java

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import java.util.Arrays;
99

1010
public class GestureHandler<T extends GestureHandler> {
11-
private final String TAG = "GestureHandler";
11+
private final String TAG = "GestureHandler";
1212

1313
public static final int STATE_UNDETERMINED = 0;
1414
public static final int STATE_FAILED = 1;
@@ -68,21 +68,23 @@ private static void initPointerProps(int size) {
6868
private GestureHandlerOrchestrator mOrchestrator;
6969
private OnTouchEventListener<T> mListener;
7070
private GestureHandlerInteractionController mInteractionController;
71-
/*package*/ int mActivationIndex; // set and accessed only by the orchestrator
72-
/*package*/ boolean mIsActive; // set and accessed only by the orchestrator
73-
/*package*/ boolean mIsAwaiting; // set and accessed only by the orchestrator
71+
int mActivationIndex;
72+
// set and accessed only by the orchestrator
73+
boolean mIsActive;
74+
// set and accessed only by the orchestrator
75+
boolean mIsAwaiting; // set and accessed only by the orchestrator
7476

7577
private static boolean hitSlopSet(float value) {
7678
return !Float.isNaN(value);
7779
}
7880

79-
/*package*/ void dispatchStateChange(int newState, int prevState) {
81+
void dispatchStateChange(int newState, int prevState) {
8082
if (mListener != null) {
8183
mListener.onStateChange((T) this, newState, prevState);
8284
}
8385
}
8486

85-
/*package*/ void dispatchTouchEvent(MotionEvent event) {
87+
void dispatchTouchEvent(MotionEvent event) {
8688
if (mListener != null) {
8789
mListener.onTouchEvent((T) this, event);
8890
}
@@ -104,7 +106,8 @@ public T setShouldCancelWhenOutside(boolean shouldCancelWhenOutside) {
104106

105107
public T setEnabled(boolean enabled) {
106108
if (mView != null) {
107-
// If view is set then handler is in "active" state. In that case we want to "cancel" handler
109+
// If view is set then handler is in "active" state. In that case we want to
110+
// "cancel" handler
108111
// when it changes enabled state so that it gets cleared from the orchestrator
109112
cancel();
110113
}
@@ -165,13 +168,15 @@ public View getView() {
165168
public float getX() {
166169
return mX;
167170
}
171+
168172
public float getXAtIndex(int index) {
169173
return mXs[index];
170174
}
171175

172176
public float getY() {
173177
return mY;
174178
}
179+
175180
public float getYAtIndex(int index) {
176181
return mYs[index];
177182
}
@@ -278,29 +283,19 @@ private MotionEvent adaptEvent(MotionEvent event) {
278283
count++;
279284
}
280285
}
281-
MotionEvent result = MotionEvent.obtain(
282-
event.getDownTime(),
283-
event.getEventTime(),
284-
action,
285-
count,
286-
sPointerProps, /* props are copied and hence it is safe to use static array here */
287-
sPointerCoords, /* same applies to coords */
288-
event.getMetaState(),
289-
event.getButtonState(),
290-
event.getXPrecision(),
291-
event.getYPrecision(),
292-
event.getDeviceId(),
293-
event.getEdgeFlags(),
294-
event.getSource(),
295-
event.getFlags());
286+
MotionEvent result = MotionEvent.obtain(event.getDownTime(), event.getEventTime(), action, count,
287+
sPointerProps, /* props are copied and hence itis safe to use static array here */
288+
sPointerCoords, /* same applies to coords */
289+
event.getMetaState(), event.getButtonState(), event.getXPrecision(), event.getYPrecision(), event.getDeviceId(),
290+
event.getEdgeFlags(), event.getSource(), event.getFlags());
296291
event.setLocation(oldX, oldY);
297292
result.setLocation(oldX, oldY);
298293
return result;
299294
}
300295

301296
public final void handle(MotionEvent origEvent) {
302-
if (!mEnabled || mState == STATE_CANCELLED || mState == STATE_FAILED
303-
|| mState == STATE_END || mTrackedPointersCount < 1) {
297+
if (!mEnabled || mState == STATE_CANCELLED || mState == STATE_FAILED || mState == STATE_END
298+
|| mTrackedPointersCount < 1) {
304299
return;
305300
}
306301
MotionEvent event = adaptEvent(origEvent);
@@ -311,13 +306,17 @@ public final void handle(MotionEvent origEvent) {
311306
mXs[index] = event.getX(index);
312307
mYs[index] = event.getY(index);
313308
}
309+
314310
mWithinBounds = isWithinBounds(mView, mX, mY);
315311
if (mShouldCancelWhenOutside && !mWithinBounds) {
316312
if (mState == STATE_ACTIVE) {
317313
cancel();
318314
} else if (mState == STATE_BEGAN) {
319315
fail();
320316
}
317+
if (event != origEvent) {
318+
event.recycle();
319+
}
321320
return;
322321
}
323322

@@ -326,6 +325,21 @@ public final void handle(MotionEvent origEvent) {
326325
mLastEventOffsetX = event.getRawX() - event.getX();
327326
mLastEventOffsetY = event.getRawY() - event.getY();
328327

328+
int action = event.getActionMasked();
329+
if(action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
330+
if (mListener != null && !mListener.shouldStartGesture((T) this, event)) {
331+
if (mState == STATE_BEGAN) {
332+
fail();
333+
} else {
334+
fail();
335+
}
336+
if (event != origEvent) {
337+
event.recycle();
338+
}
339+
return;
340+
}
341+
}
342+
329343
onHandle(event);
330344
if (event != origEvent) {
331345
event.recycle();
@@ -344,9 +358,9 @@ private void moveToState(int newState) {
344358
onStateChange(newState, oldState);
345359
}
346360

347-
public boolean wantEvents() {
348-
return mEnabled && mState != STATE_FAILED && mState != STATE_CANCELLED
349-
&& mState != STATE_END && mTrackedPointersCount > 0;
361+
public boolean wantEvents(MotionEvent event) {
362+
return mEnabled && mState != STATE_FAILED && mState != STATE_CANCELLED && mState != STATE_END
363+
&& mTrackedPointersCount > 0;
350364
}
351365

352366
public int getState() {

plugin/platforms/android/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import android.view.View;
99
import android.view.ViewGroup;
1010
import android.view.ViewParent;
11+
import android.os.SystemClock;
1112

1213
import java.util.ArrayList;
1314
import java.util.Arrays;
@@ -171,7 +172,7 @@ private void cleanupAwaitingHandlers() {
171172
mAwaitingHandlersCount = out;
172173
}
173174

174-
/* package */ void onHandlerStateChange(GestureHandler handler, int newState, int prevState) {
175+
void onHandlerStateChange(GestureHandler handler, int newState, int prevState) {
175176
mHandlingChangeSemaphore += 1;
176177
if (isFinished(newState)) {
177178
// if there were handlers awaiting completion of this handler, we can trigger
@@ -211,6 +212,13 @@ private void makeActive(GestureHandler handler) {
211212
handler.mIsActive = true;
212213
handler.mActivationIndex = mActivationIndex++;
213214

215+
// TODO: for now we do it the same as android and disable
216+
// native gestures once a gesture is recognized
217+
long time = SystemClock.uptimeMillis();
218+
MotionEvent event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0, 0, 0);
219+
event.setAction(MotionEvent.ACTION_CANCEL);
220+
handler.getView().dispatchTouchEvent(event);
221+
214222
int toCancelCount = 0;
215223
// Cancel all handlers that are required to be cancel upon current handler's
216224
// activation
@@ -289,8 +297,7 @@ private void deliverEventToGestureHandler(GestureHandler handler, MotionEvent ev
289297
handler.cancel();
290298
return;
291299
}
292-
Log.d("GestureHandlerOrchestrator", "deliverEventToGestureHandler " + handler.wantEvents());
293-
if (!handler.wantEvents()) {
300+
if (!handler.wantEvents(event)) {
294301
return;
295302
}
296303
int action = event.getActionMasked();

plugin/platforms/android/java/com/swmansion/gesturehandler/OnTouchEventListener.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import android.view.MotionEvent;
44

55
public interface OnTouchEventListener<T extends GestureHandler> {
6+
boolean shouldStartGesture(T handler, MotionEvent event);
7+
68
void onTouchEvent(T handler, MotionEvent event);
79

810
void onStateChange(T handler, int newState, int oldState);

plugin/platforms/android/java/com/swmansion/gesturehandler/TapGestureHandler.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.swmansion.gesturehandler;
22

3+
import android.util.Log;
4+
35
import android.os.Handler;
46
import android.view.MotionEvent;
57

68
public class TapGestureHandler extends GestureHandler<TapGestureHandler> {
9+
private final String TAG = "TapGestureHandler";
710
private static float MAX_VALUE_IGNORE = Float.MIN_VALUE;
811
private static final long DEFAULT_MAX_DURATION_MS = 500;
912
private static final long DEFAULT_MAX_DELAY_MS = 500;

plugin/platforms/ios/src/ForceTouchHandler.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,3 @@ - (NSMutableDictionary *)eventExtraData:(ForceTouchGestureRecognizer *)recognize
168168
}
169169

170170
@end
171-

plugin/platforms/ios/src/GestureHandler.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ if (value != nil) recognizer.prop = [value type]; \
4141
@protocol RootViewGestureRecognizerDelegate <UIGestureRecognizerDelegate>
4242

4343
@required
44-
- (void)gestureRecognizer:(nullable UIGestureRecognizer *)gestureRecognizer
44+
- (BOOL)gestureRecognizer:(nullable UIGestureRecognizer *)gestureRecognizer
4545
didActivateInRootView:(nullable UIView *)rootView;
4646

4747
@end
@@ -50,6 +50,9 @@ if (value != nil) recognizer.prop = [value type]; \
5050
@class GestureHandler;
5151
@protocol GestureHandlerDelegate <NSObject>
5252

53+
@optional
54+
- (BOOL)gestureHandler:(nullable GestureHandler *)gestureHandler shouldActivateForEvent:(nullable NSDictionary *)data;
55+
5356
@required
5457
- (void)gestureHandler:(nullable GestureHandler *)gestureHandler
5558
didChangeState:(GestureHandlerState)state prevState:(GestureHandlerState)state extraData:(nullable NSDictionary *)data view:(nullable UIView *)view;

plugin/platforms/ios/src/GestureHandler.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,18 @@ - (BOOL)containsPointInView
319319
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
320320
{
321321
[self reset];
322+
if (self.delegate && [self.delegate respondsToSelector:@selector(gestureHandler:shouldActivateForEvent:)]) {
323+
if (![self.delegate gestureHandler:self shouldActivateForEvent:[self eventExtraData:gestureRecognizer]]) {
324+
return FALSE;
325+
}
326+
}
322327
return YES;
323328
}
324329

325330
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
326331
{
332+
333+
327334
// If hitSlop is set we use it to determine if a given gesture recognizer should start processing
328335
// touch stream. This only works for negative values of hitSlop as this method won't be triggered
329336
// unless touch startes in the bounds of the attached view. To acheve similar effect with positive
@@ -347,4 +354,5 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceive
347354
// // [_eventDispatcher sendEvent:event];
348355
//}
349356

357+
350358
@end

plugin/platforms/ios/src/GestureHandlerEvents.m

Lines changed: 0 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2,100 +2,6 @@
22

33
#define SAFE_VELOCITY(velocity) @(isnan(velocity) ? 0 : velocity)
44

5-
//@implementation GestureHandlerEventExtraData
6-
//
7-
//- (instancetype)initWithData:(NSDictionary *)data;
8-
//{
9-
// if ((self = [super init])) {
10-
// _data = data;
11-
// }
12-
// return self;
13-
//}
14-
//
15-
//+ (GestureHandlerEventExtraData *)forPosition:(CGPoint)position
16-
// withAbsolutePosition:(CGPoint)absolutePosition
17-
// withNumberOfTouches:(NSUInteger)numberOfTouches
18-
//{
19-
// return [[GestureHandlerEventExtraData alloc]
20-
// initWithData:@{
21-
// @"x": @(position.x),
22-
// @"y": @(position.y),
23-
// @"absoluteX": @(absolutePosition.x),
24-
// @"absoluteY": @(absolutePosition.y),
25-
// @"numberOfPointers": @(numberOfTouches)}];
26-
//}
27-
//
28-
//+ (GestureHandlerEventExtraData *)forPan:(CGPoint)position
29-
// withAbsolutePosition:(CGPoint)absolutePosition
30-
// withTranslation:(CGPoint)translation
31-
// withVelocity:(CGPoint)velocity
32-
// withNumberOfTouches:(NSUInteger)numberOfTouches
33-
//{
34-
// return [[GestureHandlerEventExtraData alloc]
35-
// initWithData:@{
36-
// @"x": @(position.x),
37-
// @"y": @(position.y),
38-
// @"absoluteX": @(absolutePosition.x),
39-
// @"absoluteY": @(absolutePosition.y),
40-
// @"translationX": @(translation.x),
41-
// @"translationY": @(translation.y),
42-
// @"velocityX": SAFE_VELOCITY(velocity.x),
43-
// @"velocityY": SAFE_VELOCITY(velocity.y),
44-
// @"numberOfPointers": @(numberOfTouches)}];
45-
//}
46-
//
47-
//+ (GestureHandlerEventExtraData *)forForce:(CGFloat)force
48-
// forPosition:(CGPoint)position
49-
// withAbsolutePosition:(CGPoint)absolutePosition
50-
// withNumberOfTouches:(NSUInteger)numberOfTouches
51-
//{
52-
// return [[GestureHandlerEventExtraData alloc]
53-
// initWithData:@{
54-
// @"x": @(position.x),
55-
// @"y": @(position.y),
56-
// @"absoluteX": @(absolutePosition.x),
57-
// @"absoluteY": @(absolutePosition.y),
58-
// @"force": @(force),
59-
// @"numberOfPointers": @(numberOfTouches)}];
60-
//
61-
//}
62-
//
63-
//+ (GestureHandlerEventExtraData *)forPinch:(CGFloat)scale
64-
// withFocalPoint:(CGPoint)focalPoint
65-
// withVelocity:(CGFloat)velocity
66-
// withNumberOfTouches:(NSUInteger)numberOfTouches
67-
//{
68-
// return [[GestureHandlerEventExtraData alloc]
69-
// initWithData:@{
70-
// @"scale": @(scale),
71-
// @"focalX": @(focalPoint.x),
72-
// @"focalY": @(focalPoint.y),
73-
// @"velocity": SAFE_VELOCITY(velocity),
74-
// @"numberOfPointers": @(numberOfTouches)}];
75-
//}
76-
//
77-
//+ (GestureHandlerEventExtraData *)forRotation:(CGFloat)rotation
78-
// withAnchorPoint:(CGPoint)anchorPoint
79-
// withVelocity:(CGFloat)velocity
80-
// withNumberOfTouches:(NSUInteger)numberOfTouches
81-
//{
82-
// return [[GestureHandlerEventExtraData alloc]
83-
// initWithData:@{@"rotation": @(rotation),
84-
// @"anchorX": @(anchorPoint.x),
85-
// @"anchorY": @(anchorPoint.y),
86-
// @"velocity": SAFE_VELOCITY(velocity),
87-
// @"numberOfPointers": @(numberOfTouches)}];
88-
//}
89-
//
90-
//+ (GestureHandlerEventExtraData *)forPointerInside:(BOOL)pointerInside
91-
//{
92-
// return [[GestureHandlerEventExtraData alloc]
93-
// initWithData:@{@"pointerInside": @(pointerInside)}];
94-
//}
95-
//
96-
//@end
97-
98-
995
@implementation GestureHandlerEvent
1006
{
1017
NSNumber *_handlerTag;

plugin/platforms/ios/src/PanHandler.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
8686
[super touchesMoved:touches withEvent:event];
8787
if (self.state == UIGestureRecognizerStatePossible && [self shouldFailUnderCustomCriteria]) {
8888
self.state = UIGestureRecognizerStateFailed;
89+
[self reset];
8990
return;
9091
}
9192
if ((self.state == UIGestureRecognizerStatePossible || self.state == UIGestureRecognizerStateChanged)) {

0 commit comments

Comments
 (0)