From 37e807c2bc259027d2d72bc0c2823504270168c5 Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 21 May 2015 20:28:23 -0700 Subject: [PATCH] [Touches] Let only the nearest ancestor root view process touches This is to support nested root views with independent bridges by preventing touches in the inner root view from being handled by the outer one. Previously, touches were handled by both touch handlers. This was problematic because the outer touch handler would dispatch a JS touch event to the outer bridge with a react tag from the inner root's descendant view. So if you touched view 7 in the inner root view, then view 7 in the outer root view would also receive a touch event. Instead, we want touches in the inner root view to stay in the inner root view. Performance-wise, I profiled this diff and didn't see an impact. On the start of each touch (when the finger goes down, not when it is dragged), the view hierarchy is traversed upwards until the first root view which is on the order of 10 property lookups for a typical view hierarchy. Test Plan: Tapped around in an inner root view and saw that components in the outer root view like text fields, etc were no longer receiving mystery touches. --- React/Base/RCTRootView.m | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 78896f5fe482e1..26bbdde8aeab45 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -35,7 +35,7 @@ - (NSNumber *)allocateRootTag; @end -@interface RCTRootContentView : RCTView +@interface RCTRootContentView : RCTView @property (nonatomic, readonly) BOOL contentHasAppeared; @property (nonatomic, readonly, strong) RCTTouchHandler *touchHandler; @@ -327,6 +327,7 @@ - (instancetype)initWithFrame:(CGRect)frame _bridge = bridge; self.reactTag = reactTag; _touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge]; + _touchHandler.delegate = self; [self addGestureRecognizer:_touchHandler]; [_bridge.uiManager registerRootView:self withSizeFlexibility:sizeFlexibility]; self.layer.backgroundColor = NULL; @@ -381,4 +382,20 @@ - (void)invalidate } } +#pragma mark - UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch +{ + if (![gestureRecognizer isKindOfClass:[RCTTouchHandler class]]) { + return YES; + } + + UIView *currentView = touch.view; + while (currentView && ![currentView isReactRootView]) { + currentView = currentView.superview; + } + return currentView == self; +} + + @end