Skip to content

Commit

Permalink
Implement JS responder lock and prepare for proper button handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
kmagiera committed Jul 19, 2017
1 parent 452bc53 commit a328c6c
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 4 deletions.
6 changes: 6 additions & 0 deletions ios/Handlers/RNGestureHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@

@interface RNRotationGestureHandler : RNGestureHandler
@end

@interface RNRootViewGestureRecognizer : UIGestureRecognizer

- (void)blockOtherRecognizers;

@end
47 changes: 45 additions & 2 deletions ios/Handlers/RNGestureHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#import <React/UIView+React.h>
#import <React/RCTConvert.h>
#import <React/RCTScrollView.h>
#import <React/RCTTouchHandler.h>

#define VEC_LEN_SQ(pt) (pt.x * pt.x + pt.y * pt.y)

Expand Down Expand Up @@ -124,7 +126,7 @@ - (void)handleGesture:(UIGestureRecognizer *)recognizer
handlerTag:_tag
state:state
extraData:eventData];

if (state != _lastState) {
if (state == RNGestureHandlerStateEnd && _lastState != RNGestureHandlerStateActive) {
[self.emitter sendStateChangeEvent:[[RNGestureHandlerStateChange alloc] initWithRactTag:recognizer.view.reactTag
Expand All @@ -142,7 +144,7 @@ - (void)handleGesture:(UIGestureRecognizer *)recognizer
[self.emitter sendStateChangeEvent:stateEvent];
_lastState = state;
}

if (state == RNGestureHandlerStateActive) {
[self.emitter sendTouchEvent:touchEvent];
}
Expand Down Expand Up @@ -577,6 +579,21 @@ - (instancetype)initWithTag:(NSNumber *)tag
return self;
}

- (void)bindToView:(UIView *)view
{
[super bindToView:view];
// We can restore default scrollview behaviour to delay touches to scrollview's children
// because gesture handler system can handle cancellation of scroll recognizer when JS responder
// is set
if ([view isKindOfClass:[RCTScrollView class]]) {
// This part of the code is coupled with RN implementation of ScrollView native wrapper and
// we expect for RCTScrollView component to contain a subclass of UIScrollview as the only
// subview
UIScrollView *scrollView = [view.subviews objectAtIndex:0];
scrollView.delaysContentTouches = YES;
}
}

@end

#pragma mark PinchGestureHandler
Expand Down Expand Up @@ -622,3 +639,29 @@ - (RNGestureHandlerEventExtraData *)eventExtraData:(id)recognizer
}

@end

#pragma mark Root View Helpers

@implementation RNRootViewGestureRecognizer

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
{
return ![preventedGestureRecognizer isKindOfClass:[RCTTouchHandler class]];
}

- (void)blockOtherRecognizers
{
self.state = UIGestureRecognizerStateBegan;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if (self.state == UIGestureRecognizerStateBegan || self.state == UIGestureRecognizerStateChanged) {
self.state = UIGestureRecognizerStateEnded;
}
[self reset];
[super touchesEnded:touches withEvent:event];
}

@end

32 changes: 30 additions & 2 deletions ios/RNGestureHandlerManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import <React/RCTLog.h>
#import <React/RCTViewManager.h>
#import <React/RCTComponent.h>
#import <React/RCTRootView.h>

#import "RNGestureHandlerState.h"
#import "RNGestureHandler.h"
Expand All @@ -15,6 +16,7 @@ @implementation RNGestureHandlerManager
{
RNGestureHandlerRegistry *_registry;
RCTUIManager *_uiManager;
NSMutableSet<RCTRootView*> *_rootViews;
RCTEventDispatcher *_eventDispatcher;
}

Expand All @@ -25,6 +27,7 @@ - (instancetype)initWithUIManager:(RCTUIManager *)uiManager
_uiManager = uiManager;
_eventDispatcher = eventDispatcher;
_registry = [RNGestureHandlerRegistry new];
_rootViews = [NSMutableSet new];
}
return self;
}
Expand Down Expand Up @@ -61,6 +64,9 @@ - (void)createGestureHandler:(NSNumber *)viewTag

UIView *view = [_uiManager viewForReactTag:viewTag];
[gestureHandler bindToView:view];

// register root view if not already there
[self registerRootViewIfNeeded:view];
}

- (void)dropGestureHandlersForView:(NSNumber *)viewTag
Expand All @@ -70,12 +76,34 @@ - (void)dropGestureHandlersForView:(NSNumber *)viewTag

- (void)handleSetJSResponder:(NSNumber *)viewTag blockNativeResponder:(NSNumber *)blockNativeResponder
{
// TODO: js responder support
for (RCTRootView *rootView in _rootViews) {
for (UIGestureRecognizer *recognizer in rootView.gestureRecognizers) {
if ([recognizer isKindOfClass:[RNRootViewGestureRecognizer class]]) {
[(RNRootViewGestureRecognizer *)recognizer blockOtherRecognizers];
}
}
}
}

- (void)handleClearJSResponder
{
// TODO: js responder support
// ignore...
}

#pragma mark Root Views Management

- (void)registerRootViewIfNeeded:(UIView*)childView
{
UIView *parent = childView;
while (parent != nil && ![parent isKindOfClass:[RCTRootView class]]) parent = parent.superview;

RCTRootView *rootView = (RCTRootView *)parent;
if (rootView != nil && ![_rootViews containsObject:rootView]) {
[_rootViews addObject:rootView];
RNRootViewGestureRecognizer *recognizer = [RNRootViewGestureRecognizer new];
rootView.userInteractionEnabled = YES;
[rootView addGestureRecognizer:recognizer];
}
}

#pragma mark Events
Expand Down

0 comments on commit a328c6c

Please sign in to comment.