fix a tap gesture exception (#73846)

This commit is contained in:
xubaolin 2021-01-22 09:29:04 +08:00 committed by GitHub
parent 0a668b9804
commit 4bdea117a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 0 deletions

View file

@ -191,6 +191,14 @@ abstract class BaseTapGestureRecognizer extends PrimaryPointerGestureRecognizer
void addAllowedPointer(PointerDownEvent event) {
assert(event != null);
if (state == GestureRecognizerState.ready) {
// If there is no result in the previous gesture arena,
// we ignore them and prepare to accept a new pointer.
if (_down != null && _up != null) {
assert(_down!.pointer == _up!.pointer);
_reset();
}
assert(_down == null && _up == null);
// `_down` must be assigned in this method instead of `handlePrimaryPointer`,
// because `acceptGesture` might be called before `handlePrimaryPointer`,
// which relies on `_down` to call `handleTapDown`.
@ -284,6 +292,7 @@ abstract class BaseTapGestureRecognizer extends PrimaryPointerGestureRecognizer
if (!_wonArenaForPrimaryPointer || _up == null) {
return;
}
assert(_up!.pointer == _down!.pointer);
handleTapUp(down: _down!, up: _up!);
_reset();
}

View file

@ -622,4 +622,39 @@ void main() {
recognized.clear();
doubleTap.dispose();
});
// Regression test for https://github.com/flutter/flutter/issues/73667
testGesture('Unfinished DoubleTap does not prevent competing Tap', (GestureTester tester) {
int tapCount = 0;
final DoubleTapGestureRecognizer doubleTap = DoubleTapGestureRecognizer()
..onDoubleTap = () {};
final TapGestureRecognizer tap = TapGestureRecognizer()
..onTap = () => tapCount++;
// Open a arena with 2 members and holding.
doubleTap.addPointer(down1);
tap.addPointer(down1);
tester.closeArena(1);
tester.route(down1);
tester.route(up1);
GestureBinding.instance!.gestureArena.sweep(1);
// Open a new arena with only one TapGestureRecognizer.
tester.async.elapse(const Duration(milliseconds: 100));
tap.addPointer(down2);
tester.closeArena(2);
tester.route(down2);
final PointerMoveEvent move2 = PointerMoveEvent(pointer: 2, position: down2.position);
tester.route(move2);
tester.route(up2);
expect(tapCount, 1); // The second tap will win immediately.
GestureBinding.instance!.gestureArena.sweep(2);
// Finish the previous gesture arena.
tester.async.elapse(const Duration(milliseconds: 300));
expect(tapCount, 1); // The first tap should not trigger onTap callback though it wins the arena.
tap.dispose();
doubleTap.dispose();
});
}