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
Fix TextField
horizontal drag conflicts
#147341
Conversation
TextField
drag conflicts
08935d9
to
d5bd704
Compare
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.
Here's my understanding, tell me if anything is wrong:
For the case where a TextField is inside of a horizontal scrollable on iOS, dragging the selection handle should move the selection handle and not scroll. On other platforms, it should scroll horizontally.
The current behavior is that it always scrolls horizontally. The reason is that the touchSlop on the scrollable is less than the touchSlop on the selection handle. When the drag exceeds the lower touchSlop, that recognizer immediately wins.
What would happen if the touchSlops were identical? By having different touchSlops, are we sidestepping the part of the gesture arena where two competing recognizers decide who receives the gesture?
Are the different touchSlops intentional, like we know that native recognizes these drags after different distances?
I want to understand whether this is a canonical Flutter solution to competing gesture detectors, or if not, make sure that this is a compromise that we're willing to make. If so I'm totally on board, this looks like a pretty straightforward change.
if (_start != null && !eagerVictoryOnDrag) { | ||
assert(_dragState == _DragState.possible); | ||
assert(currentUp == null); | ||
_dragState = _DragState.accepted; |
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.
Why is this not set in the previous if
too?
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.
Because in the case of eagerVictoryOnDrag == true
, it is set immediately when the drag is detected.
@@ -1924,6 +1929,7 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S | |||
(PanGestureRecognizer instance) { | |||
instance | |||
..dragStartBehavior = widget.dragStartBehavior | |||
..gestureSettings = eagerlyAcceptDragWhenCollapsed ? const DeviceGestureSettings(touchSlop: 1.0) : null |
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.
Why 1.0? Could it be competing-slop-value minus one, or is 1.0 better? (I know you said you're still thinking about cleaning this up.)
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 like the idea of competing-slop-value minus one, or maybe minus something higher than 1 to be sure that it always wins.
@@ -2839,16 +2823,6 @@ class TextSelectionGestureDetectorBuilder { | |||
case PointerDeviceKind.invertedStylus: | |||
case PointerDeviceKind.touch: | |||
case PointerDeviceKind.unknown: | |||
// For iOS platforms, a touch drag does not initiate unless the |
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.
Where is this removed logic covered now? I guess the drag listener on the selection handle?
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.
Yeah the drag listener on the selection handle already has this logic by default.
On iOS the current behavior is that the On Android the current behavior is that the The changes in this PR only affect iOS at the moment.
If
Delaying the drag acceptance until all other recognizers have lost is similar to what we do with |
c96862d
to
69ec079
Compare
TextField
drag conflictsTextField
horizontal drag conflicts
ab83353
to
8db991f
Compare
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 with nits 👍
Thanks for talking this over with me yesterday and for the clear explanation of the changes in the PR description, it saved me some time in understanding everything.
tester.route(pointer.up()); | ||
expect(events, <String>[ | ||
'panstart', | ||
'panend']); |
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.
Super nit: I would typically do
'panend',
]);
expect(dismissed, true); | ||
}, | ||
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }), | ||
); |
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.
Nit: Consider also testing the behavior for this on the other platforms (cursor is not dragged).
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'll add these tests in a follow up PR that changes the Android/Fuchsia behavior.
…t can always beat other gestures
Fix leak introduced by #147341
Roll Flutter from d33bb8fa5eb8 to bf7191fd3884 (34 revisions) flutter/flutter@d33bb8f...bf7191f 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from b989d239e281 to 1fb36ac9d718 (2 revisions) (flutter/flutter#147713) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3c9c2ce8369e to b989d239e281 (1 revision) (flutter/flutter#147711) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 58b031c096ea to 3c9c2ce8369e (2 revisions) (flutter/flutter#147703) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from fc28057dbd4d to 58b031c096ea (1 revision) (flutter/flutter#147701) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from bfc6787eedc3 to fc28057dbd4d (1 revision) (flutter/flutter#147700) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 7cbef71f4f54 to bfc6787eedc3 (1 revision) (flutter/flutter#147699) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 90ce9e5959fc to 7cbef71f4f54 (1 revision) (flutter/flutter#147696) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 78dced50c467 to 90ce9e5959fc (1 revision) (flutter/flutter#147695) 2024-05-02 andrewrkolos@gmail.com add verbose logging to select hot reload/hot restart tests (flutter/flutter#147673) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3087ec1adddd to 78dced50c467 (3 revisions) (flutter/flutter#147693) 2024-05-02 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Implement computeDryBaseline for `RenderWrap` (#146260)" (flutter/flutter#147692) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from f56c20c6ac67 to 3087ec1adddd (2 revisions) (flutter/flutter#147688) 2024-05-02 gspencergoog@users.noreply.github.com Allow explicit exclusion of packages from pinned packages in `flutter update-packages --force-update` (flutter/flutter#147679) 2024-05-02 31859944+LongCatIsLooong@users.noreply.github.com Implement getDryBaseline for Stack and Overlay (flutter/flutter#146253) 2024-05-02 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2d73fa207927 to f56c20c6ac67 (2 revisions) (flutter/flutter#147681) 2024-05-02 polinach@google.com Update selectable_text_test.dart (flutter/flutter#147677) 2024-05-01 engine-flutter-autoroll@skia.org Roll Flutter Engine from c536a14052e5 to 2d73fa207927 (2 revisions) (flutter/flutter#147678) 2024-05-01 31859944+LongCatIsLooong@users.noreply.github.com Implement computeDryBaseline for `RenderWrap` (flutter/flutter#146260) 2024-05-01 engine-flutter-autoroll@skia.org Roll Flutter Engine from 842cf254ec58 to c536a14052e5 (1 revision) (flutter/flutter#147675) 2024-05-01 49699333+dependabot[bot]@users.noreply.github.com Bump codecov/codecov-action from 4.3.0 to 4.3.1 (flutter/flutter#147674) 2024-05-01 ian@hixie.ch Remove obsolete performance analysis tools. (flutter/flutter#147663) 2024-05-01 engine-flutter-autoroll@skia.org Roll Flutter Engine from 5129b4919434 to 842cf254ec58 (3 revisions) (flutter/flutter#147670) 2024-05-01 120297255+PurplePolyhedron@users.noreply.github.com fix DropdownMenu overflow (flutter/flutter#147233) 2024-05-01 yjbanov@google.com [web] remove platform_messages_integration test (flutter/flutter#147654) 2024-05-01 rmolivares@renzo-olivares.dev Fix `TextField` horizontal drag conflicts (flutter/flutter#147341) 2024-05-01 nate.w5687@gmail.com `flutter/lib/src/`: refactoring if-chains into switch expressions (flutter/flutter#147472) 2024-05-01 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Draggable feedback positioning (#145647)" (flutter/flutter#147658) 2024-05-01 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0014e0353aa9 to 5129b4919434 (1 revision) (flutter/flutter#147655) 2024-05-01 yjbanov@google.com add lang attribute to the a11y_assessments app (flutter/flutter#147586) 2024-05-01 hi@timcreated.it Draggable feedback positioning (flutter/flutter#145647) 2024-05-01 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0ce67714ce4c to 0014e0353aa9 (13 revisions) (flutter/flutter#147649) 2024-05-01 sokolovskyi.konstantin@gmail.com Add test for animated_fractionally_sized_box.0.dart API example. (flutter/flutter#146721) 2024-05-01 engine-flutter-autoroll@skia.org Roll Packages from cc47b06 to aea93d2 (5 revisions) (flutter/flutter#147647) 2024-05-01 73608287+ellet0@users.noreply.github.com Update reorderable_list.dart to use Dart 3 return switch statement for consistency (flutter/flutter#147505) 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 dit@google.com,rmistry@google.com,stuartmorgan@google.com 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://issues.skia.org/issues/new?component=1389291&template=1850622 ...
Currently on iOS
TextField
horizontal drag gestures will have precedence over parent horizontal drag gestures when competing with each other because the defaulttouchSlop
value used byTextField
to calculate whether the threshold for a drag has been met is the same as the one used by parent horizontal drag gestures likePageView
, and otherScrollable
s. The default value is18.0
, and because theTextField
receives thePointerEvent
first in this scenario, it always declares victory before any parent horizontal drag gestures has the chance to.Native iOS behavior: The parent horizontal drag gestures will always win unless the drag originated on the cursor (collapsed selection), in that case the TextField cursor drag gestures will win.
This change:
BaseTapAndDragGestureRecognizer.eagerVictoryOnDrag
which can be used to configure the recognizer to declare victory immediately when it detects a drag, or when disabled it will wait until it is the last recognizer in the arena before declaring victory. The default behavior is that it declares victory immediately when the drag is detected.TextSelectionGestureDetector
, this logic is now delegated to the selection handle overlay which already had this logic in place.eagerVictoryOnDrag
for iOS to allow for parent drag gestures to win and match native behavior.Fixes #124421, Fixes #130198, Fixes #142624, Fixes #142447, Fixes #127017
Pre-launch Checklist
///
).