Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 36ca574

Browse files
author
Chris Yang
authored
[platform_views] Fix duplicated touch event pass down to flutter view from platform view. (#8026)
Fix for flutter/flutter#27700 and flutter/flutter#24207 There are 2 fixes included in this PR. The intercepting views sometime pass up the touches events to flutter view, even after the forward gesture recognizer pass the event to the flutter view. We only want the event to be passed to the flutter view once. So we let the intercepting view 'consumes' the event in this PR to fix the problem. When a touch sequence has multiple touch points participated(e.g. Pinch gesture), the touchesBegan and touchesEnded can be triggered multiple times if the touches do not happen simultaneously. One example would be: when performing a pinch gesture with 2 fingers, I put down one finger, keep the finger on the screen, then put down another finger, perform pinch, lift up both finger at the same time. In this sequence, touchesBegan is called twice with each touch in one of the calls and touchesEnded is called once and has 2 touches in the callback. To handle this issue, we added a count to count the touches in one touch sequence. We only set the state to fail when the count reaches 0(That is all the touches has began in the current sequence is ended).
1 parent 3d53e20 commit 36ca574

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,21 @@ - (void)blockGesture {
353353
_delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
354354
}
355355

356+
// We want the intercepting view to consume the touches and not pass the touches up to the parent
357+
// view. Make the touch event method not call super will not pass the touches up to the parent view.
358+
// Hence we overide the touch event methods and do nothing.
359+
- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
360+
}
361+
362+
- (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
363+
}
364+
365+
- (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
366+
}
367+
368+
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
369+
}
370+
356371
@end
357372

358373
@implementation DelayingGestureRecognizer {
@@ -395,19 +410,24 @@ @implementation ForwardingGestureRecognizer {
395410
// So this is safe as when FlutterView is deallocated the reference to ForwardingGestureRecognizer
396411
// will go away.
397412
UIView* _flutterView;
413+
// Counting the pointers that has started in one touch sequence.
414+
NSInteger _currentTouchPointersCount;
398415
}
399416

400417
- (instancetype)initWithTarget:(id)target flutterView:(UIView*)flutterView {
401418
self = [super initWithTarget:target action:nil];
402419
if (self) {
403420
self.delegate = self;
404421
_flutterView = flutterView;
422+
_currentTouchPointersCount = 0;
405423
}
406424
return self;
407425
}
408426

409427
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
410428
[_flutterView touchesBegan:touches withEvent:event];
429+
_currentTouchPointersCount += touches.count;
430+
[_flutterView touchesBegan:touches withEvent:event];
411431
}
412432

413433
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
@@ -416,11 +436,19 @@ - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
416436

417437
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
418438
[_flutterView touchesEnded:touches withEvent:event];
419-
self.state = UIGestureRecognizerStateFailed;
439+
_currentTouchPointersCount -= touches.count;
440+
// Touches in one touch sequence are sent to the touchesEnded method separately if different
441+
// fingers stop touching the screen at different time. So one touchesEnded method triggering does
442+
// not necessarially mean the touch sequence has ended. We Only set the state to
443+
// UIGestureRecognizerStateFailed when all the touches in the current touch sequence is ended.
444+
if (_currentTouchPointersCount == 0) {
445+
self.state = UIGestureRecognizerStateFailed;
446+
}
420447
}
421448

422449
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
423450
[_flutterView touchesCancelled:touches withEvent:event];
451+
_currentTouchPointersCount = 0;
424452
self.state = UIGestureRecognizerStateFailed;
425453
}
426454

0 commit comments

Comments
 (0)