[ReactNative] Properly transition RCTTouchHandler state

Summary:
When touches end or cancel, update self.state in
RCTTouchHandler to let iOS know that we are in an ended/canceled state.
This way we won't eat other touches because it still thinks we're in a
began/changed state.

@public

Test Plan:
Scrolling in the back swipe area no longer busts gesture
recognition in Wilde.
This commit is contained in:
Nick Lockwood 2015-05-05 05:58:07 -07:00
parent 1a17cceb17
commit acafa7e921
2 changed files with 48 additions and 17 deletions

View File

@ -55,8 +55,9 @@
_pendingTouches = [[NSMutableArray alloc] init]; _pendingTouches = [[NSMutableArray alloc] init];
_bridgeInteractionTiming = [[NSMutableArray alloc] init]; _bridgeInteractionTiming = [[NSMutableArray alloc] init];
// `cancelsTouchesInView` is needed in order to be used as a top level event delegated recognizer. Otherwise, lower // `cancelsTouchesInView` is needed in order to be used as a top level
// level components not build using RCT, will fail to recognize gestures. // event delegated recognizer. Otherwise, lower-level components not built
// using RCT, will fail to recognize gestures.
self.cancelsTouchesInView = NO; self.cancelsTouchesInView = NO;
} }
return self; return self;
@ -165,7 +166,9 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
* (start/end/move/cancel) and the indices that represent "changed" `Touch`es * (start/end/move/cancel) and the indices that represent "changed" `Touch`es
* from that array. * from that array.
*/ */
- (void)_updateAndDispatchTouches:(NSSet *)touches eventName:(NSString *)eventName originatingTime:(CFTimeInterval)originatingTime - (void)_updateAndDispatchTouches:(NSSet *)touches
eventName:(NSString *)eventName
originatingTime:(CFTimeInterval)originatingTime
{ {
// Update touches // Update touches
NSMutableArray *changedIndexes = [[NSMutableArray alloc] init]; NSMutableArray *changedIndexes = [[NSMutableArray alloc] init];
@ -196,15 +199,39 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
#pragma mark - Gesture Recognizer Delegate Callbacks #pragma mark - Gesture Recognizer Delegate Callbacks
static BOOL RCTAllTouchesAreCancelldOrEnded(NSSet *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan ||
touch.phase == UITouchPhaseMoved ||
touch.phase == UITouchPhaseStationary) {
return NO;
}
}
return YES;
}
static BOOL RCTAnyTouchesChanged(NSSet *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan ||
touch.phase == UITouchPhaseMoved) {
return YES;
}
}
return NO;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{ {
[super touchesBegan:touches withEvent:event]; [super touchesBegan:touches withEvent:event];
self.state = UIGestureRecognizerStateBegan;
// "start" has to record new touches before extracting the event. // "start" has to record new touches before extracting the event.
// "end"/"cancel" needs to remove the touch *after* extracting the event. // "end"/"cancel" needs to remove the touch *after* extracting the event.
[self _recordNewTouches:touches]; [self _recordNewTouches:touches];
[self _updateAndDispatchTouches:touches eventName:@"topTouchStart" originatingTime:event.timestamp]; [self _updateAndDispatchTouches:touches eventName:@"topTouchStart" originatingTime:event.timestamp];
self.state = UIGestureRecognizerStateBegan;
} }
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
@ -213,7 +240,12 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
if (self.state == UIGestureRecognizerStateFailed) { if (self.state == UIGestureRecognizerStateFailed) {
return; return;
} }
[self _updateAndDispatchTouches:touches eventName:@"topTouchMove" originatingTime:event.timestamp]; [self _updateAndDispatchTouches:touches eventName:@"topTouchMove" originatingTime:event.timestamp];
if (self.state == UIGestureRecognizerStateBegan) {
self.state = UIGestureRecognizerStateChanged;
}
} }
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
@ -221,6 +253,12 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
[super touchesEnded:touches withEvent:event]; [super touchesEnded:touches withEvent:event];
[self _updateAndDispatchTouches:touches eventName:@"topTouchEnd" originatingTime:event.timestamp]; [self _updateAndDispatchTouches:touches eventName:@"topTouchEnd" originatingTime:event.timestamp];
[self _recordRemovedTouches:touches]; [self _recordRemovedTouches:touches];
if (RCTAllTouchesAreCancelldOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateEnded;
} else if (RCTAnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
} }
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
@ -228,6 +266,12 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
[super touchesCancelled:touches withEvent:event]; [super touchesCancelled:touches withEvent:event];
[self _updateAndDispatchTouches:touches eventName:@"topTouchCancel" originatingTime:event.timestamp]; [self _updateAndDispatchTouches:touches eventName:@"topTouchCancel" originatingTime:event.timestamp];
[self _recordRemovedTouches:touches]; [self _recordRemovedTouches:touches];
if (RCTAllTouchesAreCancelldOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateCancelled;
} else if (RCTAnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
} }
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer

View File

@ -702,19 +702,6 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
} }
} }
float containerMainAxis = node->layout.dimensions[dim[mainAxis]];
// If the user didn't specify a width or height, and it has not been set
// by the container, then we set it via the children.
if (isUndefined(containerMainAxis)) {
containerMainAxis = fmaxf(
// We're missing the last padding at this point to get the final
// dimension
boundAxis(node, mainAxis, mainDim + getPaddingAndBorder(node, trailing[mainAxis])),
// We can never assign a width smaller than the padding and borders
getPaddingAndBorderAxis(node, mainAxis)
);
}
float containerCrossAxis = node->layout.dimensions[dim[crossAxis]]; float containerCrossAxis = node->layout.dimensions[dim[crossAxis]];
if (isUndefined(node->layout.dimensions[dim[crossAxis]])) { if (isUndefined(node->layout.dimensions[dim[crossAxis]])) {
containerCrossAxis = fmaxf( containerCrossAxis = fmaxf(