Commit 3d7a4eed authored by amirh's avatar amirh Committed by GitHub

Short circuit _checkUp if tap callbacks were triggered by resolve. (#12521)

parent bd3e91ed
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'arena.dart';
import 'constants.dart';
import 'events.dart';
......@@ -90,6 +92,8 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
if (event is PointerUpEvent) {
_finalPosition = event.position;
_checkUp();
} else if (event is PointerCancelEvent) {
_reset();
}
}
......@@ -143,6 +147,14 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
void _checkUp() {
if (_wonArenaForPrimaryPointer && _finalPosition != null) {
resolve(GestureDisposition.accepted);
if (!_wonArenaForPrimaryPointer || _finalPosition == null) {
// It is possible that resolve has just recursively called _checkUp
// (see https://github.com/flutter/flutter/issues/12470).
// In that case _wonArenaForPrimaryPointer will be false (as _checkUp
// calls _reset) and we return here to avoid double invocation of the
// tap callbacks.
return;
}
if (onTapUp != null)
invokeCallback<Null>('onTapUp', () { onTapUp(new TapUpDetails(globalPosition: _finalPosition)); });
if (onTap != null)
......@@ -159,4 +171,12 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
@override
String get debugDescription => 'tap';
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
description.add(new FlagProperty('wonArenaForPrimaryPointer', value: _wonArenaForPrimaryPointer, ifTrue: 'won arena'));
description.add(new DiagnosticsProperty<Offset>('finalPosition', _finalPosition, defaultValue: null));
description.add(new FlagProperty('sentTapDown', value: _sentTapDown, ifTrue: 'sent tap down'));
}
}
......@@ -43,7 +43,7 @@ void main() {
GestureBinding.instance.gestureArena.sweep(1);
expect(log, hasLength(2));
expect(log[0], equalsIgnoringHashCodes('Gesture arena 1 ❙ Sweeping with 1 member.'));
expect(log[1], equalsIgnoringHashCodes('Gesture arena 1 ❙ Winner: TapGestureRecognizer#00000(state: ready)'));
expect(log[1], equalsIgnoringHashCodes('Gesture arena 1 ❙ Winner: TapGestureRecognizer#00000(state: ready, finalPosition: Offset(12.0, 8.0))'));
log.clear();
tap.dispose();
......@@ -83,9 +83,9 @@ void main() {
GestureBinding.instance.gestureArena.sweep(1);
expect(log, hasLength(3));
expect(log[0], equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready) calling onTapDown callback.'));
expect(log[1], equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready) calling onTapUp callback.'));
expect(log[2], equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready) calling onTap callback.'));
expect(log[0], equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready, finalPosition: Offset(12.0, 8.0)) calling onTapDown callback.'));
expect(log[1], equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready, won arena, finalPosition: Offset(12.0, 8.0), sent tap down) calling onTapUp callback.'));
expect(log[2], equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready, won arena, finalPosition: Offset(12.0, 8.0), sent tap down) calling onTap callback.'));
log.clear();
tap.dispose();
......@@ -132,10 +132,10 @@ void main() {
GestureBinding.instance.gestureArena.sweep(1);
expect(log, hasLength(5));
expect(log[0], equalsIgnoringHashCodes('Gesture arena 1 ❙ Sweeping with 1 member.'));
expect(log[1], equalsIgnoringHashCodes('Gesture arena 1 ❙ Winner: TapGestureRecognizer#00000(state: ready)'));
expect(log[2], equalsIgnoringHashCodes(' ❙ TapGestureRecognizer#00000(state: ready) calling onTapDown callback.'));
expect(log[3], equalsIgnoringHashCodes(' ❙ TapGestureRecognizer#00000(state: ready) calling onTapUp callback.'));
expect(log[4], equalsIgnoringHashCodes(' ❙ TapGestureRecognizer#00000(state: ready) calling onTap callback.'));
expect(log[1], equalsIgnoringHashCodes('Gesture arena 1 ❙ Winner: TapGestureRecognizer#00000(state: ready, finalPosition: Offset(12.0, 8.0))'));
expect(log[2], equalsIgnoringHashCodes(' ❙ TapGestureRecognizer#00000(state: ready, finalPosition: Offset(12.0, 8.0)) calling onTapDown callback.'));
expect(log[3], equalsIgnoringHashCodes(' ❙ TapGestureRecognizer#00000(state: ready, won arena, finalPosition: Offset(12.0, 8.0), sent tap down) calling onTapUp callback.'));
expect(log[4], equalsIgnoringHashCodes(' ❙ TapGestureRecognizer#00000(state: ready, won arena, finalPosition: Offset(12.0, 8.0), sent tap down) calling onTap callback.'));
log.clear();
tap.dispose();
......@@ -145,4 +145,13 @@ void main() {
debugPrintRecognizerCallbacksTrace = false;
debugPrint = oldCallback;
});
test('TapGestureRecognizer _sentTapDown toString', () {
final TapGestureRecognizer tap = new TapGestureRecognizer();
expect(tap.toString(), equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: ready)'));
final PointerEvent event = const PointerDownEvent(pointer: 1, position: const Offset(10.0, 10.0));
tap.addPointer(event);
tap.didExceedDeadline();
expect(tap.toString(), equalsIgnoringHashCodes('TapGestureRecognizer#00000(state: possible, sent tap down)'));
});
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
void main() {
testWidgets('onTap detection with canceled pointer and a drag listener', (WidgetTester tester) async {
int detector1TapCount = 0;
int detector2TapCount = 0;
final Widget widget = new GestureDetector(
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new GestureDetector(
onTap: () { detector1TapCount += 1; },
behavior: HitTestBehavior.opaque,
child: const SizedBox(width: 200.0, height: 200.0),
),
new GestureDetector(
onTap: () { detector2TapCount += 1; },
behavior: HitTestBehavior.opaque,
child: const SizedBox(width: 200.0, height: 200.0)
)
],
)
);
await tester.pumpWidget(widget);
// The following pointer event sequence was causing the issue described
// in https://github.com/flutter/flutter/issues/12470 by triggering 2 tap
// events on the second detector.
final TestGesture gesture1 = await tester.startGesture(const Offset(400.0, 10.0));
final TestGesture gesture2 = await tester.startGesture(const Offset(400.0, 210.0));
await gesture1.up();
await gesture2.cancel();
final TestGesture gesture3 = await tester.startGesture(const Offset(400.0, 250.0));
await gesture3.up();
expect(detector1TapCount, 1);
expect(detector2TapCount, 1);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment