-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Allow long-press gestures to continue even if buttons change. #127877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this is a very obscure user interaction, option 1 did sound reasonable to me and it looks like we do something similar by handling down (accepted) -> cancel in TapGestureRecognizer.
flutter/packages/flutter/lib/src/gestures/tap.dart
Lines 257 to 268 in f92f441
| @override | |
| void resolve(GestureDisposition disposition) { | |
| if (_wonArenaForPrimaryPointer && disposition == GestureDisposition.rejected) { | |
| // This can happen if the gesture has been canceled. For example, when | |
| // the pointer has exceeded the touch slop, the buttons have been changed, | |
| // or if the recognizer is disposed. | |
| assert(_sentTapDown); | |
| _checkCancel(null, 'spontaneous'); | |
| _reset(); | |
| } | |
| super.resolve(disposition); | |
| } |
But I agree with the point that it wouldn't fix current users. I wonder if in the future we want to provide the
buttons in the gesture details object so a user could potentially handle this use-case by checking if the initial down buttons are the same as the end buttons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From testing on macOS, after this first move4, when releasing the primary button, another move event is dispatched with the buttons set as 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be outside of the scope of this PR, but when testing on macOS and web with a local example app the buttons of this final PointerUpEvent is actually 0. Is this expected?
|
Can you elaborate on what you're seeing on macOS? In general I would hope that we normalize our inputs so the same physical inputs turn into the same events at the Flutter level but that may be optimistic. I'm happy to add tests for other sequences, to make sure they all make sense. Is that what you had in mind? |
|
Using this example app with the change in this PR. import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: GestureDetector(
onLongPressStart: (LongPressStartDetails details) {
debugPrint('start');
},
onLongPressMoveUpdate: (LongPressMoveUpdateDetails details) {
debugPrint('move');
},
onLongPressEnd: (LongPressEndDetails details) {
debugPrint('end');
},
child: Container(
color: Colors.green,
height: 200,
width: 200,
child: const Text('Hello World!'),
),
),
),
),
);
}
}and adding some logging in For the following click sequence.
This is what I see in the logs for macOS native/and macOS chrome. I was more or less wondering if we should test that extra |
|
I can add some tests that check that sequence and others, sure. |
Previously, if you changed buttons during a long-press gesture, if it was before the gesture was accepted we would discard it, and if it was after the gesture was accepted we would silently end it without firing any of the relevant events. This silent cancelation behavior is terrible because it means there's no way for consumers to know what state they're in, so you end up with widgets that thing they're still being long-pressed even though nothing is happening. We could change the behavior in three ways, as far as I can tell: - we could send a cancel event when you change buttons. This would introduce a new kind of transition (start->cancel) which I don't think we currently require people to support. This would therefore not fix existing code and would make future code more complicated to handle a really obscure user action that it seems unlikely anyone cares about. - we could send an end event when you change buttons. This would mean the action commits, even though the user is still holding the mouse button down. This seems slightly better than the previous option but still not ideal as it means nudging the mouse button commits you even though you're still holding the button down. - we could ignore button changes after the long-press has been accepted. I implemented the last one in this PR.
|
@Renzo-Olivares PTAL |
Renzo-Olivares
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
I think the broken google testing may have been unrelated since it was having some issues around the time when this PR was approved. |
flutter/flutter@35085c3...bc49cd1 2023-07-06 [email protected] Allow long-press gestures to continue even if buttons change. (flutter/flutter#127877) 2023-07-06 [email protected] Enable unreachable_from_main lint - it is stable now!!1 (flutter/flutter#129854) 2023-07-06 [email protected] Update labeler to new label names (flutter/flutter#130040) 2023-07-05 [email protected] MergeableMaterial: Fix adding a slice and separating it (flutter/flutter#128804) 2023-07-05 [email protected] Update infrastructure issue template for new priority scheme (flutter/flutter#129741) 2023-07-05 [email protected] Fix typo in canvas example (flutter/flutter#129879) 2023-07-05 [email protected] Reland Fix AnimatedList & AnimatedGrid doesn't apply MediaQuery padding #129556 (flutter/flutter#129860) 2023-07-05 [email protected] Change from "created via performance template" to "from: performance template" (flutter/flutter#130035) 2023-07-05 [email protected] Removes deprecated APIs from v2.6 in `binding.dart` and `widget_tester.dart` (flutter/flutter#129663) 2023-07-05 [email protected] Add new hot reload case string (flutter/flutter#130008) 2023-07-05 [email protected] Manual roll Flutter Engine from 987b621eac4e to bd2e42b203e1 (32 revisions) (flutter/flutter#130023) 2023-07-05 [email protected] Add simple unit tests for annotations.dart file (flutter/flutter#128902) 2023-07-05 [email protected] fix a bug when android uses CupertinoPageTransitionsBuilder... (flutter/flutter#114303) 2023-07-05 [email protected] Add .env file support for option `--dart-define-from-file` (flutter/flutter#128668) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Previously, if you changed buttons during a long-press gesture, if it was before the gesture was accepted we would discard it, and if it was after the gesture was accepted we would silently end it without firing any of the relevant events.
This silent cancelation behavior is terrible because it means there's no way for consumers to know what state they're in, so you end up with widgets that thing they're still being long-pressed even though nothing is happening.
We could change the behavior in three ways, as far as I can tell:
we could send a cancel event when you change buttons. This would introduce a new kind of transition (start->cancel) which I don't think we currently require people to support. This would therefore not fix existing code and would make future code more complicated to handle a really obscure user action that it seems unlikely anyone cares about.
we could send an end event when you change buttons. This would mean the action commits, even though the user is still holding the mouse button down. This seems slightly better than the previous option but still not ideal as it means nudging the mouse button commits you even though you're still holding the button down.
we could ignore button changes after the long-press has been accepted.
I implemented the last one in this PR.