Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
6a75dc44
Unverified
Commit
6a75dc44
authored
May 01, 2020
by
Greg Spencer
Committed by
GitHub
May 01, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add onSecondaryTap to gesture recognizer and gesture detector. (#55494)
parent
f1c24ed9
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
514 additions
and
229 deletions
+514
-229
events.dart
packages/flutter/lib/src/gestures/events.dart
+1
-1
long_press.dart
packages/flutter/lib/src/gestures/long_press.dart
+129
-24
tap.dart
packages/flutter/lib/src/gestures/tap.dart
+26
-8
gesture_detector.dart
packages/flutter/lib/src/widgets/gesture_detector.dart
+94
-1
gesture_detector_test.dart
packages/flutter/test/widgets/gesture_detector_test.dart
+264
-195
No files found.
packages/flutter/lib/src/gestures/events.dart
View file @
6a75dc44
...
...
@@ -30,7 +30,7 @@ const int kPrimaryButton = 0x01;
/// It is equivalent to:
///
/// * [kPrimaryStylusButton]: The stylus contacts the screen.
/// * [kSecondaryMouseButton]: The
prim
ary mouse button.
/// * [kSecondaryMouseButton]: The
second
ary mouse button.
///
/// See also:
///
...
...
packages/flutter/lib/src/gestures/long_press.dart
View file @
6a75dc44
...
...
@@ -141,9 +141,9 @@ class LongPressEndDetails {
/// moved, triggering [onLongPressMoveUpdate] callbacks, unless the
/// [postAcceptSlopTolerance] constructor argument is specified.
///
/// [LongPressGestureRecognizer]
competes on pointer events of [kPrimaryButton]
///
only when it has at least one non-null callback. If it has no callbacks, it
/// is a no-op.
/// [LongPressGestureRecognizer]
may compete on pointer events of
///
[kPrimaryButton] and/or [kSecondaryButton] if at least one corresponding
///
callback is non-null. If it has no callbacks, it
is a no-op.
class
LongPressGestureRecognizer
extends
PrimaryPointerGestureRecognizer
{
/// Creates a long-press gesture recognizer.
///
...
...
@@ -225,6 +225,57 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
/// callback.
GestureLongPressEndCallback
onLongPressEnd
;
/// Called when a long press gesture by a secondary button has been
/// recognized.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPressStart], which has the same timing but has data for
/// the press location.
GestureLongPressCallback
onSecondaryLongPress
;
/// Called when a long press gesture by a secondary button has been recognized.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPress], which has the same timing but without details.
/// * [LongPressStartDetails], which is passed as an argument to this
/// callback.
GestureLongPressStartCallback
onSecondaryLongPressStart
;
/// Called when moving after the long press by a secondary button is
/// recognized.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [LongPressMoveUpdateDetails], which is passed as an argument to this
/// callback.
GestureLongPressMoveUpdateCallback
onSecondaryLongPressMoveUpdate
;
/// Called when the pointer stops contacting the screen after a long-press by
/// a secondary button.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPressEnd], which has the same timing but has data for
/// the up gesture location.
GestureLongPressUpCallback
onSecondaryLongPressUp
;
/// Called when the pointer stops contacting the screen after a long-press by
/// a secondary button.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPressUp], which has the same timing, but without
/// details.
/// * [LongPressEndDetails], which is passed as an argument to this callback.
GestureLongPressEndCallback
onSecondaryLongPressEnd
;
VelocityTracker
_velocityTracker
;
@override
...
...
@@ -238,6 +289,14 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
onLongPressUp
==
null
)
return
false
;
break
;
case
kSecondaryButton:
if
(
onSecondaryLongPressStart
==
null
&&
onSecondaryLongPress
==
null
&&
onSecondaryLongPressMoveUpdate
==
null
&&
onSecondaryLongPressEnd
==
null
&&
onSecondaryLongPressUp
==
null
)
return
false
;
break
;
default
:
return
false
;
}
...
...
@@ -291,37 +350,67 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
}
void
_checkLongPressStart
()
{
assert
(
_initialButtons
==
kPrimaryButton
);
if
(
onLongPressStart
!=
null
)
{
final
LongPressStartDetails
details
=
LongPressStartDetails
(
globalPosition:
_longPressOrigin
.
global
,
localPosition:
_longPressOrigin
.
local
,
);
invokeCallback
<
void
>(
'onLongPressStart'
,
()
=>
onLongPressStart
(
details
));
switch
(
_initialButtons
)
{
case
kPrimaryButton:
if
(
onLongPressStart
!=
null
)
{
final
LongPressStartDetails
details
=
LongPressStartDetails
(
globalPosition:
_longPressOrigin
.
global
,
localPosition:
_longPressOrigin
.
local
,
);
invokeCallback
<
void
>(
'onLongPressStart'
,
()
=>
onLongPressStart
(
details
));
}
if
(
onLongPress
!=
null
)
{
invokeCallback
<
void
>(
'onLongPress'
,
onLongPress
);
}
break
;
case
kSecondaryButton:
if
(
onSecondaryLongPressStart
!=
null
)
{
final
LongPressStartDetails
details
=
LongPressStartDetails
(
globalPosition:
_longPressOrigin
.
global
,
localPosition:
_longPressOrigin
.
local
,
);
invokeCallback
<
void
>(
'onSecondaryLongPressStart'
,
()
=>
onSecondaryLongPressStart
(
details
));
}
if
(
onSecondaryLongPress
!=
null
)
{
invokeCallback
<
void
>(
'onSecondaryLongPress'
,
onSecondaryLongPress
);
}
break
;
default
:
assert
(
false
,
'Unhandled button
$_initialButtons
'
);
}
if
(
onLongPress
!=
null
)
invokeCallback
<
void
>(
'onLongPress'
,
onLongPress
);
}
void
_checkLongPressMoveUpdate
(
PointerEvent
event
)
{
assert
(
_initialButtons
==
kPrimaryButton
);
final
LongPressMoveUpdateDetails
details
=
LongPressMoveUpdateDetails
(
globalPosition:
event
.
position
,
localPosition:
event
.
localPosition
,
offsetFromOrigin:
event
.
position
-
_longPressOrigin
.
global
,
localOffsetFromOrigin:
event
.
localPosition
-
_longPressOrigin
.
local
,
);
if
(
onLongPressMoveUpdate
!=
null
)
invokeCallback
<
void
>(
'onLongPressMoveUpdate'
,
()
=>
onLongPressMoveUpdate
(
details
));
switch
(
_initialButtons
)
{
case
kPrimaryButton:
if
(
onLongPressMoveUpdate
!=
null
)
{
invokeCallback
<
void
>(
'onLongPressMoveUpdate'
,
()
=>
onLongPressMoveUpdate
(
details
));
}
break
;
case
kSecondaryButton:
if
(
onSecondaryLongPressMoveUpdate
!=
null
)
{
invokeCallback
<
void
>(
'onSecondaryLongPressMoveUpdate'
,
()
=>
onSecondaryLongPressMoveUpdate
(
details
));
}
break
;
default
:
assert
(
false
,
'Unhandled button
$_initialButtons
'
);
}
}
void
_checkLongPressEnd
(
PointerEvent
event
)
{
assert
(
_initialButtons
==
kPrimaryButton
);
final
VelocityEstimate
estimate
=
_velocityTracker
.
getVelocityEstimate
();
final
Velocity
velocity
=
estimate
==
null
?
Velocity
.
zero
:
Velocity
(
pixelsPerSecond:
estimate
.
pixelsPerSecond
);
final
Velocity
velocity
=
estimate
==
null
?
Velocity
.
zero
:
Velocity
(
pixelsPerSecond:
estimate
.
pixelsPerSecond
);
final
LongPressEndDetails
details
=
LongPressEndDetails
(
globalPosition:
event
.
position
,
localPosition:
event
.
localPosition
,
...
...
@@ -329,10 +418,26 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
);
_velocityTracker
=
null
;
if
(
onLongPressEnd
!=
null
)
invokeCallback
<
void
>(
'onLongPressEnd'
,
()
=>
onLongPressEnd
(
details
));
if
(
onLongPressUp
!=
null
)
invokeCallback
<
void
>(
'onLongPressUp'
,
onLongPressUp
);
switch
(
_initialButtons
)
{
case
kPrimaryButton:
if
(
onLongPressEnd
!=
null
)
{
invokeCallback
<
void
>(
'onLongPressEnd'
,
()
=>
onLongPressEnd
(
details
));
}
if
(
onLongPressUp
!=
null
)
{
invokeCallback
<
void
>(
'onLongPressUp'
,
onLongPressUp
);
}
break
;
case
kSecondaryButton:
if
(
onSecondaryLongPressEnd
!=
null
)
{
invokeCallback
<
void
>(
'onSecondaryLongPressEnd'
,
()
=>
onSecondaryLongPressEnd
(
details
));
}
if
(
onSecondaryLongPressUp
!=
null
)
{
invokeCallback
<
void
>(
'onSecondaryLongPressUp'
,
onSecondaryLongPressUp
);
}
break
;
default
:
assert
(
false
,
'Unhandled button
$_initialButtons
'
);
}
}
void
_reset
()
{
...
...
packages/flutter/lib/src/gestures/tap.dart
View file @
6a75dc44
...
...
@@ -369,7 +369,7 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
/// of a primary button.
///
/// This triggers on the up event, if the recognizer wins the arena with it
/// or has previously won, immediately following [onTap].
/// or has previously won, immediately following [onTap
Up
].
///
/// If this recognizer doesn't win the arena, [onTapCancel] is called instead.
///
...
...
@@ -396,6 +396,22 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
/// * [GestureDetector.onTapCancel], which exposes this callback.
GestureTapCancelCallback
onTapCancel
;
/// A pointer has stopped contacting the screen, which is recognized as a tap
/// of a secondary button.
///
/// This triggers on the up event, if the recognizer wins the arena with it or
/// has previously won, immediately following [onSecondaryTapUp].
///
/// If this recognizer doesn't win the arena, [onSecondaryTapCancel] is called
/// instead.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryTapUp], which has the same timing but with details.
/// * [GestureDetector.onSecondaryTap], which exposes this callback.
GestureTapCallback
onSecondaryTap
;
/// A pointer has contacted the screen at a particular location with a
/// secondary button, which might be the start of a secondary tap.
///
...
...
@@ -424,6 +440,8 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
///
/// See also:
///
/// * [onSecondaryTap], a handler triggered right after this one that doesn't
/// pass any details about the tap.
/// * [kSecondaryButton], the button this callback responds to.
/// * [onTapUp], a similar callback but for a primary button.
/// * [TapUpDetails], which is passed as an argument to this callback.
...
...
@@ -456,7 +474,8 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
return
false
;
break
;
case
kSecondaryButton:
if
(
onSecondaryTapDown
==
null
&&
if
(
onSecondaryTap
==
null
&&
onSecondaryTapDown
==
null
&&
onSecondaryTapUp
==
null
&&
onSecondaryTapCancel
==
null
)
return
false
;
...
...
@@ -482,8 +501,7 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
break
;
case
kSecondaryButton:
if
(
onSecondaryTapDown
!=
null
)
invokeCallback
<
void
>(
'onSecondaryTapDown'
,
()
=>
onSecondaryTapDown
(
details
));
invokeCallback
<
void
>(
'onSecondaryTapDown'
,
()
=>
onSecondaryTapDown
(
details
));
break
;
default
:
}
...
...
@@ -505,8 +523,9 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
break
;
case
kSecondaryButton:
if
(
onSecondaryTapUp
!=
null
)
invokeCallback
<
void
>(
'onSecondaryTapUp'
,
()
=>
onSecondaryTapUp
(
details
));
invokeCallback
<
void
>(
'onSecondaryTapUp'
,
()
=>
onSecondaryTapUp
(
details
));
if
(
onSecondaryTap
!=
null
)
invokeCallback
<
void
>(
'onSecondaryTap'
,
()
=>
onSecondaryTap
());
break
;
default
:
}
...
...
@@ -523,8 +542,7 @@ class TapGestureRecognizer extends BaseTapGestureRecognizer {
break
;
case
kSecondaryButton:
if
(
onSecondaryTapCancel
!=
null
)
invokeCallback
<
void
>(
'
${note}
onSecondaryTapCancel'
,
onSecondaryTapCancel
);
invokeCallback
<
void
>(
'
${note}
onSecondaryTapCancel'
,
onSecondaryTapCancel
);
break
;
default
:
}
...
...
packages/flutter/lib/src/widgets/gesture_detector.dart
View file @
6a75dc44
...
...
@@ -189,6 +189,7 @@ class GestureDetector extends StatelessWidget {
this
.
onTapUp
,
this
.
onTap
,
this
.
onTapCancel
,
this
.
onSecondaryTap
,
this
.
onSecondaryTapDown
,
this
.
onSecondaryTapUp
,
this
.
onSecondaryTapCancel
,
...
...
@@ -198,6 +199,11 @@ class GestureDetector extends StatelessWidget {
this
.
onLongPressMoveUpdate
,
this
.
onLongPressUp
,
this
.
onLongPressEnd
,
this
.
onSecondaryLongPress
,
this
.
onSecondaryLongPressStart
,
this
.
onSecondaryLongPressMoveUpdate
,
this
.
onSecondaryLongPressUp
,
this
.
onSecondaryLongPressEnd
,
this
.
onVerticalDragDown
,
this
.
onVerticalDragStart
,
this
.
onVerticalDragUpdate
,
...
...
@@ -304,6 +310,18 @@ class GestureDetector extends StatelessWidget {
/// * [kPrimaryButton], the button this callback responds to.
final
GestureTapCancelCallback
onTapCancel
;
/// A tap with a secondary button has occurred.
///
/// This triggers when the tap gesture wins. If the tap gesture did not win,
/// [onSecondaryTapCancel] is called instead.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryTapUp], which is called at the same time but includes details
/// regarding the pointer position.
final
GestureTapCallback
onSecondaryTap
;
/// A pointer that might cause a tap with a secondary button has contacted the
/// screen at a particular location.
///
...
...
@@ -324,6 +342,8 @@ class GestureDetector extends StatelessWidget {
///
/// See also:
///
/// * [onSecondaryTap], a handler triggered right after this one that doesn't
/// pass any details about the tap.
/// * [kSecondaryButton], the button this callback responds to.
final
GestureTapUpCallback
onSecondaryTapUp
;
...
...
@@ -394,6 +414,59 @@ class GestureDetector extends StatelessWidget {
/// details.
final
GestureLongPressEndCallback
onLongPressEnd
;
/// Called when a long press gesture with a secondary button has been
/// recognized.
///
/// Triggered when a pointer has remained in contact with the screen at the
/// same location for a long period of time.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPressStart], which has the same timing but has gesture
/// details.
final
GestureLongPressCallback
onSecondaryLongPress
;
/// Called when a long press gesture with a secondary button has been
/// recognized.
///
/// Triggered when a pointer has remained in contact with the screen at the
/// same location for a long period of time.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPress], which has the same timing but without the
/// gesture details.
final
GestureLongPressStartCallback
onSecondaryLongPressStart
;
/// A pointer has been drag-moved after a long press with a secondary button.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
final
GestureLongPressMoveUpdateCallback
onSecondaryLongPressMoveUpdate
;
/// A pointer that has triggered a long-press with a secondary button has
/// stopped contacting the screen.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPressEnd], which has the same timing but has gesture
/// details.
final
GestureLongPressUpCallback
onSecondaryLongPressUp
;
/// A pointer that has triggered a long-press with a secondary button has
/// stopped contacting the screen.
///
/// See also:
///
/// * [kSecondaryButton], the button this callback responds to.
/// * [onSecondaryLongPressUp], which has the same timing but without the
/// gesture details.
final
GestureLongPressEndCallback
onSecondaryLongPressEnd
;
/// A pointer has contacted the screen with a primary button and might begin
/// to move vertically.
///
...
...
@@ -601,6 +674,7 @@ class GestureDetector extends StatelessWidget {
onTapUp
!=
null
||
onTap
!=
null
||
onTapCancel
!=
null
||
onSecondaryTap
!=
null
||
onSecondaryTapDown
!=
null
||
onSecondaryTapUp
!=
null
||
onSecondaryTapCancel
!=
null
...
...
@@ -613,6 +687,7 @@ class GestureDetector extends StatelessWidget {
..
onTapUp
=
onTapUp
..
onTap
=
onTap
..
onTapCancel
=
onTapCancel
..
onSecondaryTap
=
onSecondaryTap
..
onSecondaryTapDown
=
onSecondaryTapDown
..
onSecondaryTapUp
=
onSecondaryTapUp
..
onSecondaryTapCancel
=
onSecondaryTapCancel
;
...
...
@@ -647,6 +722,24 @@ class GestureDetector extends StatelessWidget {
);
}
if
(
onSecondaryLongPress
!=
null
||
onSecondaryLongPressUp
!=
null
||
onSecondaryLongPressStart
!=
null
||
onSecondaryLongPressMoveUpdate
!=
null
||
onSecondaryLongPressEnd
!=
null
)
{
gestures
[
LongPressGestureRecognizer
]
=
GestureRecognizerFactoryWithHandlers
<
LongPressGestureRecognizer
>(
()
=>
LongPressGestureRecognizer
(
debugOwner:
this
),
(
LongPressGestureRecognizer
instance
)
{
instance
..
onSecondaryLongPress
=
onSecondaryLongPress
..
onSecondaryLongPressStart
=
onSecondaryLongPressStart
..
onSecondaryLongPressMoveUpdate
=
onSecondaryLongPressMoveUpdate
..
onSecondaryLongPressEnd
=
onSecondaryLongPressEnd
..
onSecondaryLongPressUp
=
onSecondaryLongPressUp
;
},
);
}
if
(
onVerticalDragDown
!=
null
||
onVerticalDragStart
!=
null
||
onVerticalDragUpdate
!=
null
||
...
...
@@ -1110,7 +1203,7 @@ abstract class SemanticsGestureDelegate {
// For readers who come here to learn how to write custom semantics delegates:
// this is not a proper sample code. It has access to the detector state as well
// as its private properties, which are inaccessible normally. It is designed
// this way in order to work independenly in a [RawGestureRecognizer] to
// this way in order to work independen
t
ly in a [RawGestureRecognizer] to
// preserve existing behavior.
//
// Instead, a normal delegate will store callbacks as properties, and use them
...
...
packages/flutter/test/widgets/gesture_detector_test.dart
View file @
6a75dc44
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment