diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 3452807bcdeb5..2bd198af6bf12 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -353,6 +353,21 @@ - (void)blockGesture { _delayingRecognizer.get().state = UIGestureRecognizerStateEnded; } +// We want the intercepting view to consume the touches and not pass the touches up to the parent +// view. Make the touch event method not call super will not pass the touches up to the parent view. +// Hence we overide the touch event methods and do nothing. +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { +} + +- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { +} + @end @implementation DelayingGestureRecognizer { @@ -395,6 +410,8 @@ @implementation ForwardingGestureRecognizer { // So this is safe as when FlutterView is deallocated the reference to ForwardingGestureRecognizer // will go away. UIView* _flutterView; + // Counting the pointers that has started in one touch sequence. + NSInteger _currentTouchPointersCount; } - (instancetype)initWithTarget:(id)target flutterView:(UIView*)flutterView { @@ -402,12 +419,15 @@ - (instancetype)initWithTarget:(id)target flutterView:(UIView*)flutterView { if (self) { self.delegate = self; _flutterView = flutterView; + _currentTouchPointersCount = 0; } return self; } - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { [_flutterView touchesBegan:touches withEvent:event]; + _currentTouchPointersCount += touches.count; + [_flutterView touchesBegan:touches withEvent:event]; } - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { @@ -416,11 +436,19 @@ - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { [_flutterView touchesEnded:touches withEvent:event]; - self.state = UIGestureRecognizerStateFailed; + _currentTouchPointersCount -= touches.count; + // Touches in one touch sequence are sent to the touchesEnded method separately if different + // fingers stop touching the screen at different time. So one touchesEnded method triggering does + // not necessarially mean the touch sequence has ended. We Only set the state to + // UIGestureRecognizerStateFailed when all the touches in the current touch sequence is ended. + if (_currentTouchPointersCount == 0) { + self.state = UIGestureRecognizerStateFailed; + } } - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { [_flutterView touchesCancelled:touches withEvent:event]; + _currentTouchPointersCount = 0; self.state = UIGestureRecognizerStateFailed; }