diff --git a/packages/flutter/lib/gestures.dart b/packages/flutter/lib/gestures.dart index f5432bc455..15acba77e3 100644 --- a/packages/flutter/lib/gestures.dart +++ b/packages/flutter/lib/gestures.dart @@ -13,5 +13,4 @@ export 'src/gestures/long_press.dart'; export 'src/gestures/pointer_router.dart'; export 'src/gestures/recognizer.dart'; export 'src/gestures/scale.dart'; -export 'src/gestures/show_press.dart'; export 'src/gestures/tap.dart'; diff --git a/packages/flutter/lib/src/gestures/constants.dart b/packages/flutter/lib/src/gestures/constants.dart index fd8fa38c22..a1cac5da2e 100644 --- a/packages/flutter/lib/src/gestures/constants.dart +++ b/packages/flutter/lib/src/gestures/constants.dart @@ -5,8 +5,8 @@ // Modeled after Android's ViewConfiguration: // https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewConfiguration.java -const Duration kLongPressTimeout = const Duration(milliseconds: 500); const Duration kPressTimeout = const Duration(milliseconds: 100); +const Duration kLongPressTimeout = const Duration(milliseconds: 500); const Duration kJumpTapTimeout = const Duration(milliseconds: 500); const Duration kDoubleTapTimeout = const Duration(milliseconds: 300); const Duration kDoubleTapMinTime = const Duration(milliseconds: 40); diff --git a/packages/flutter/lib/src/gestures/show_press.dart b/packages/flutter/lib/src/gestures/show_press.dart deleted file mode 100644 index 1ecc4f7622..0000000000 --- a/packages/flutter/lib/src/gestures/show_press.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 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 'arena.dart'; -import 'constants.dart'; -import 'events.dart'; -import 'recognizer.dart'; - -typedef void GestureShowPressCallback(); - -class ShowPressGestureRecognizer extends PrimaryPointerGestureRecognizer { - ShowPressGestureRecognizer({ PointerRouter router, this.onShowPress }) - : super(router: router, deadline: kPressTimeout); - - GestureShowPressCallback onShowPress; - - void didExceedDeadline() { - // Show press isn't an exclusive gesture. We can recognize a show press - // as well as another gesture, like a long press. - resolve(GestureDisposition.rejected); - onShowPress(); - } - - void handlePrimaryPointer(PointerInputEvent event) { - if (event.type == 'pointerup') - resolve(GestureDisposition.rejected); - } -} diff --git a/packages/flutter/lib/src/gestures/tap.dart b/packages/flutter/lib/src/gestures/tap.dart index a28155faf3..c0d6420ea6 100644 --- a/packages/flutter/lib/src/gestures/tap.dart +++ b/packages/flutter/lib/src/gestures/tap.dart @@ -26,31 +26,34 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { this.onTapUp, this.onTap, this.onTapCancel - }) : super(router: router); + }) : super(router: router, deadline: kPressTimeout); GestureTapDownCallback onTapDown; GestureTapDownCallback onTapUp; GestureTapCallback onTap; GestureTapCancelCallback onTapCancel; + bool _sentTapDown = false; bool _wonArena = false; Point _finalPosition; void handlePrimaryPointer(PointerInputEvent event) { - if (event.type == 'pointerdown') { - if (onTapDown != null) - onTapDown(event.position); - } else if (event.type == 'pointerup') { + if (event.type == 'pointerup') { _finalPosition = event.position; - _check(); + _checkUp(); } } + void didExceedDeadline() { + _checkDown(); + } + void acceptGesture(int pointer) { super.acceptGesture(pointer); if (pointer == primaryPointer) { + _checkDown(); _wonArena = true; - _check(); + _checkUp(); } } @@ -64,7 +67,15 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { } } - void _check() { + void _checkDown() { + if (!_sentTapDown) { + if (onTapDown != null) + onTapDown(initialPosition); + _sentTapDown = true; + } + } + + void _checkUp() { if (_wonArena && _finalPosition != null) { resolve(GestureDisposition.accepted); if (onTapUp != null) @@ -76,6 +87,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { } void _reset() { + _sentTapDown = false; _wonArena = false; _finalPosition = null; } diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index 0d50e1b598..21eb524c7a 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; import 'dart:math' as math; import 'package:flutter/animation.dart'; @@ -88,13 +87,8 @@ class _InkSplash { curve: Curves.easeOut ), duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor()) - )..addListener(_handleRadiusChange); - - // Wait kPressTimeout to avoid creating tiny splashes during scrolls. - // TODO(ianh): Instead of a timer in _InkSplash, we should start splashes from the gesture recognisers' onTapDown. - // ...and onTapDown should use a timer _or_ fire as soon as the tap is committed. - // When we do this, make sure it works even if we're only listening to onLongPress. - _startTimer = new Timer(kPressTimeout, _play); + )..addListener(_handleRadiusChange) + ..play(); } final Point position; @@ -103,45 +97,26 @@ class _InkSplash { double _targetRadius; double _pinnedRadius; ValuePerformance _radius; - Timer _startTimer; - - bool _cancelStartTimer() { - if (_startTimer != null) { - _startTimer.cancel(); - _startTimer = null; - return true; - } - return false; - } - - void _play() { - _cancelStartTimer(); - _radius.play(); - } void _updateVelocity(double velocity) { int duration = (_targetRadius / velocity).floor(); _radius.duration = new Duration(milliseconds: duration); - _play(); + _radius.play(); } void confirm() { - if (_cancelStartTimer()) - return; _updateVelocity(_kSplashConfirmedVelocity); _pinnedRadius = null; } void cancel() { - if (_cancelStartTimer()) - return; _updateVelocity(_kSplashCanceledVelocity); _pinnedRadius = _radius.value; } void _handleRadiusChange() { if (_radius.value == _targetRadius) - renderer._splashes.remove(this); + renderer._removeSplash(this); renderer.markNeedsPaint(); } @@ -183,15 +158,21 @@ class _RenderInkSplashes extends RenderProxyBox { _HighlightChangedCallback onHighlightChanged; final List<_InkSplash> _splashes = new List<_InkSplash>(); + _InkSplash _lastSplash; TapGestureRecognizer _tap; LongPressGestureRecognizer _longPress; + void _removeSplash(_InkSplash splash) { + _splashes.remove(splash); + if (_lastSplash == splash) + _lastSplash = null; + } + void handleEvent(InputEvent event, BoxHitTestEntry entry) { - if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) { + if (event.type == 'pointerdown' && (onTap != null || onLongPress != null)) { _tap?.addPointer(event); _longPress?.addPointer(event); - _splashes.add(new _InkSplash(entry.localPosition, this)); } } @@ -208,7 +189,7 @@ class _RenderInkSplashes extends RenderProxyBox { } void _syncTapRecognizer() { - if (onTap == null) { + if (onTap == null && onLongPress == null) { _disposeTapRecognizer(); } else { _tap ??= new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter) @@ -237,31 +218,34 @@ class _RenderInkSplashes extends RenderProxyBox { _longPress = null; } - void _handleTapDown(_) { + void _handleTapDown(Point position) { + _lastSplash = new _InkSplash(globalToLocal(position), this); + _splashes.add(_lastSplash); if (onHighlightChanged != null) onHighlightChanged(true); } void _handleTap() { - if (_splashes.isNotEmpty) - _splashes.last.confirm(); - + _lastSplash?.confirm(); + _lastSplash = null; if (onHighlightChanged != null) onHighlightChanged(false); - if (onTap != null) onTap(); } void _handleTapCancel() { - _splashes.last?.cancel(); + _lastSplash?.cancel(); + _lastSplash = null; if (onHighlightChanged != null) onHighlightChanged(false); } void _handleLongPress() { - _splashes.last?.confirm(); - onLongPress(); + _lastSplash?.confirm(); + _lastSplash = null; + if (onLongPress != null) + onLongPress(); } void paint(PaintingContext context, Offset offset) { diff --git a/packages/flutter/lib/src/widgets/gesture_detector.dart b/packages/flutter/lib/src/widgets/gesture_detector.dart index 5ac26e579a..d1659ebeb6 100644 --- a/packages/flutter/lib/src/widgets/gesture_detector.dart +++ b/packages/flutter/lib/src/widgets/gesture_detector.dart @@ -13,7 +13,6 @@ export 'package:flutter/gestures.dart' show GestureTapUpCallback, GestureTapCallback, GestureTapCancelCallback, - GestureShowPressCallback, GestureLongPressCallback, GestureDragStartCallback, GestureDragUpdateCallback, @@ -37,7 +36,6 @@ class GestureDetector extends StatefulComponent { this.onTap, this.onTapCancel, this.onDoubleTap, - this.onShowPress, this.onLongPress, this.onVerticalDragStart, this.onVerticalDragUpdate, @@ -61,7 +59,6 @@ class GestureDetector extends StatefulComponent { final GestureTapCancelCallback onTapCancel; final GestureTapCallback onDoubleTap; - final GestureShowPressCallback onShowPress; final GestureLongPressCallback onLongPress; final GestureDragStartCallback onVerticalDragStart; @@ -88,7 +85,6 @@ class _GestureDetectorState extends State { TapGestureRecognizer _tap; DoubleTapGestureRecognizer _doubleTap; - ShowPressGestureRecognizer _showPress; LongPressGestureRecognizer _longPress; VerticalDragGestureRecognizer _verticalDrag; HorizontalDragGestureRecognizer _horizontalDrag; @@ -107,7 +103,6 @@ class _GestureDetectorState extends State { void dispose() { _tap = _ensureDisposed(_tap); _doubleTap = _ensureDisposed(_doubleTap); - _showPress = _ensureDisposed(_showPress); _longPress = _ensureDisposed(_longPress); _verticalDrag = _ensureDisposed(_verticalDrag); _horizontalDrag = _ensureDisposed(_horizontalDrag); @@ -119,7 +114,6 @@ class _GestureDetectorState extends State { void _syncAll() { _syncTap(); _syncDoubleTap(); - _syncShowPress(); _syncLongPress(); _syncVerticalDrag(); _syncHorizontalDrag(); @@ -149,15 +143,6 @@ class _GestureDetectorState extends State { } } - void _syncShowPress() { - if (config.onShowPress == null) { - _showPress = _ensureDisposed(_showPress); - } else { - _showPress ??= new ShowPressGestureRecognizer(router: _router); - _showPress.onShowPress = config.onShowPress; - } - } - void _syncLongPress() { if (config.onLongPress == null) { _longPress = _ensureDisposed(_longPress); @@ -227,8 +212,6 @@ class _GestureDetectorState extends State { _tap.addPointer(event); if (_doubleTap != null) _doubleTap.addPointer(event); - if (_showPress != null) - _showPress.addPointer(event); if (_longPress != null) _longPress.addPointer(event); if (_verticalDrag != null) @@ -255,8 +238,6 @@ class _GestureDetectorState extends State { gestures.add('tap'); if (_doubleTap != null) gestures.add('double tap'); - if (_showPress != null) - gestures.add('show press'); if (_longPress != null) gestures.add('long press'); if (_verticalDrag != null) diff --git a/packages/unit/test/gestures/long_press_test.dart b/packages/unit/test/gestures/long_press_test.dart index ce95e3ab27..1871112d47 100644 --- a/packages/unit/test/gestures/long_press_test.dart +++ b/packages/unit/test/gestures/long_press_test.dart @@ -67,14 +67,14 @@ void main() { longPress.dispose(); }); - test('Should recognize both show press and long press', () { + test('Should recognize both tap down and long press', () { PointerRouter router = new PointerRouter(); - ShowPressGestureRecognizer showPress = new ShowPressGestureRecognizer(router: router); + TapGestureRecognizer tap = new TapGestureRecognizer(router: router); LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router); - bool showPressRecognized = false; - showPress.onShowPress = () { - showPressRecognized = true; + bool tapDownRecognized = false; + tap.onTapDown = (_) { + tapDownRecognized = true; }; bool longPressRecognized = false; @@ -83,23 +83,23 @@ void main() { }; new FakeAsync().run((FakeAsync async) { - showPress.addPointer(down); + tap.addPointer(down); longPress.addPointer(down); GestureArena.instance.close(5); - expect(showPressRecognized, isFalse); + expect(tapDownRecognized, isFalse); expect(longPressRecognized, isFalse); router.route(down); - expect(showPressRecognized, isFalse); + expect(tapDownRecognized, isFalse); expect(longPressRecognized, isFalse); async.elapse(new Duration(milliseconds: 300)); - expect(showPressRecognized, isTrue); + expect(tapDownRecognized, isTrue); expect(longPressRecognized, isFalse); async.elapse(new Duration(milliseconds: 700)); - expect(showPressRecognized, isTrue); + expect(tapDownRecognized, isTrue); expect(longPressRecognized, isTrue); }); - showPress.dispose(); + tap.dispose(); longPress.dispose(); }); } diff --git a/packages/unit/test/gestures/show_press_test.dart b/packages/unit/test/gestures/show_press_test.dart deleted file mode 100644 index 1206fbf52f..0000000000 --- a/packages/unit/test/gestures/show_press_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:quiver/testing/async.dart'; -import 'package:flutter/gestures.dart'; -import 'package:test/test.dart'; - -final PointerInputEvent down = new PointerInputEvent( - pointer: 5, - type: 'pointerdown', - x: 10.0, - y: 10.0 -); - -final PointerInputEvent up = new PointerInputEvent( - pointer: 5, - type: 'pointerup', - x: 11.0, - y: 9.0 -); - -void main() { - test('Should recognize show press', () { - PointerRouter router = new PointerRouter(); - ShowPressGestureRecognizer showPress = new ShowPressGestureRecognizer(router: router); - - bool showPressRecognized = false; - showPress.onShowPress = () { - showPressRecognized = true; - }; - - new FakeAsync().run((FakeAsync async) { - showPress.addPointer(down); - GestureArena.instance.close(5); - expect(showPressRecognized, isFalse); - router.route(down); - expect(showPressRecognized, isFalse); - async.elapse(new Duration(milliseconds: 300)); - expect(showPressRecognized, isTrue); - }); - - showPress.dispose(); - }); - - test('Up cancels show press', () { - PointerRouter router = new PointerRouter(); - ShowPressGestureRecognizer showPress = new ShowPressGestureRecognizer(router: router); - - bool showPressRecognized = false; - showPress.onShowPress = () { - showPressRecognized = true; - }; - - new FakeAsync().run((FakeAsync async) { - showPress.addPointer(down); - GestureArena.instance.close(5); - expect(showPressRecognized, isFalse); - router.route(down); - expect(showPressRecognized, isFalse); - async.elapse(new Duration(milliseconds: 50)); - expect(showPressRecognized, isFalse); - router.route(up); - expect(showPressRecognized, isFalse); - async.elapse(new Duration(seconds: 1)); - expect(showPressRecognized, isFalse); - }); - - showPress.dispose(); - }); -}