Skip to content

[framework] make hit slop based on device pointer kind for drag/pan/scale gestures#64267

Merged
jonahwilliams merged 10 commits intoflutter:masterfrom
jonahwilliams:sloppy_touch
Sep 8, 2020
Merged

[framework] make hit slop based on device pointer kind for drag/pan/scale gestures#64267
jonahwilliams merged 10 commits intoflutter:masterfrom
jonahwilliams:sloppy_touch

Conversation

@jonahwilliams
Copy link
Contributor

@jonahwilliams jonahwilliams commented Aug 20, 2020

Description

Currently the framework uses fairly large "hit slop" values to disambiguate taps from drags/pans. This makes sense on touch devices where the interaction is not very precise, on mice however it can feel as if the UI is lagging. This is immediately noticeable on our infra dashboard, where it takes almost half of a grid square of drag before the actual drag kicks in.

One potential solution is to always use smaller constants depending on whether the interaction is mouse or touch based. The only reasonable choice is to use the pointer device kind and not target platform - same platform can have different input sources. This requires exposing the pointer device kind in a few new places in several of the gesture detectors, and using the enum to compute the correct hit slop from an expanded set of constants.

This almost works, however there are a few places (notably ListViews) which uses the touch hit slop as a default value in scroll physics. It does not seem like it will be easy to disambiguate a user provided scroll physics constant from the default and/or adjust it somehow - this might require significant changes to scroll physics which I have left out of this PR.

This PR does not adjust:

kTouchSlop used in scroll_physics.dart's minFlingDistance
kTouchSlop used in PrimaryPointerGestureRecognizer/LongPressGestureRecognizer

Before:

before

After:

after

@flutter-dashboard flutter-dashboard bot added framework flutter/packages/flutter repository. See also f: labels. work in progress; do not review labels Aug 20, 2020
double computeHitSlop(PointerDeviceKind kind) {
switch (kind) {
case PointerDeviceKind.mouse:
case PointerDeviceKind.stylus:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsure if stylus should be treated like mouse or touch, probably the latter to be safe.

@jonahwilliams jonahwilliams changed the title [framework] make hit slop based on device pointer kind [framework] make hit slop based on device pointer kind for drag/pan/scale gestures Aug 21, 2020
@jonahwilliams jonahwilliams marked this pull request as ready for review August 21, 2020 17:48
@goderbauer goderbauer added the a: desktop Running on desktop label Aug 24, 2020
final bool isPostAcceptSlopPastTolerance =
_gestureAccepted &&
postAcceptSlopTolerance != null &&
postAcceptSlopTolerance != null &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@goderbauer goderbauer added the f: gestures flutter/packages/flutter/gestures repository. label Aug 24, 2020
@goderbauer
Copy link
Member

/cc @gspencergoog @dkwingsmt for desktop and gesture stuff.

double computeHitSlop(PointerDeviceKind kind) {
switch (kind) {
case PointerDeviceKind.mouse:
case PointerDeviceKind.stylus:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure whether styles is more a mouse or touch device...

Copy link
Contributor Author

@jonahwilliams jonahwilliams Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I have no idea really. The only stylus I've ever used was the one that came with the Nintendo DS. In that case, it was more of a precision assist for the existing touch screen. I could imagine for a stylus like that it would not be disambiguated from a touch event.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol, I see you asked the same question above...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And people often use stylii in place of mice when they use it on a drawing surface. I think of stylii as being much more precise than touch, so I'd go with the more precise slop on them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know!

@jonahwilliams
Copy link
Contributor Author

Of course the other question is should the mouse slop be smaller? We could always file an issue and ask for feedback

@jonahwilliams
Copy link
Contributor Author

Friendly ping @gspencergoog @dkwingsmt

const Duration kJumpTapTimeout = Duration(milliseconds: 500);

/// Like [kTouchSlop], but for mouse pointers.
const double kMouseHitSlop = 1.0; // Logical pixels;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be using the word "Mouse" in these? I think something like "kPrecisePointerHitSlop" is more correct, since it wouldn't have to be a mouse (trackpads would have this set too, for instance). We use "precise" as terminology elsewhere (but we also use mouse some places too).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to follow the precisePointer pattern

double computeHitSlop(PointerDeviceKind kind) {
switch (kind) {
case PointerDeviceKind.mouse:
case PointerDeviceKind.stylus:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And people often use stylii in place of mice when they use it on a drawing surface. I think of stylii as being much more precise than touch, so I'd go with the more precise slop on them.

super(debugOwner: debugOwner, kind: kind);

static VelocityTracker _defaultBuilder(PointerEvent ev) => VelocityTracker();
static VelocityTracker _defaultBuilder(PointerEvent ev) => VelocityTracker(ev.kind);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it'd be nice if the variable was called event instead of just ev.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

case TargetPlatform.iOS:
case TargetPlatform.macOS:
return (PointerEvent ev) => IOSScrollViewFlingVelocityTracker();
return (PointerEvent ev) => IOSScrollViewFlingVelocityTracker(ev.kind);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename ev to event here (and below) too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32384589-a60f0e74-c078-11e7-9bc1-e5b5287aea9d

@jonahwilliams jonahwilliams merged commit 2989881 into flutter:master Sep 8, 2020
@jonahwilliams jonahwilliams deleted the sloppy_touch branch September 8, 2020 22:53
@jamesblasco
Copy link
Contributor

jamesblasco commented Sep 13, 2020

Hello @jonahwilliams. I am using VelocityTracker for a package and this is a breaking change for me.

Looking at the code it looks like VelocityTracker doesn't depend in PointerDeviceKind to calculate the velocity no?
Could I use VelocityTracker(PointerDeviceKind.unknown) directly?

@jonahwilliams
Copy link
Contributor Author

The pointer device type is used to configure the amount of touch/drag/pan slop. If you use unknown you will always have touch level low precision.

@orischwartz
Copy link
Contributor

This change broke builds involving any library that used VelocityTracker() without the required parameter.

Any chance this can be modified to take an optional parameter defaulting to PointerDeviceKind.touch?

Here's an example of a popular plugin that broke when building against beta channel: akshathjain/sliding_up_panel#193

@viplifes
Copy link

viplifes commented Sep 17, 2020

@TahaTesser This change broke another popular plugin jamesblasco/modal_bottom_sheet#69

@goderbauer
Copy link
Member

To avoid being broken by changes in Flutter, consider adding the tests of your packages to https://github.com/flutter/tests as per policy here: https://flutter.dev/docs/resources/compatibility.

@yunior123
Copy link

yunior123 commented Sep 17, 2020

I am using flutter with the mp_chart library and this is the error I am getting
/opt/hostedtoolcache/flutter/1.22.0-12.1.pre-beta/x64/.pub-cache/hosted/pub.dartlang.org/optimized_gesture_detector-0.0.5/lib/scale.dart:229:55: Error: Too few positional arguments: 1 required, 0 given.

_velocityTrackers[event.pointer] = VelocityTracker();

Any idea on how to solve it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: desktop Running on desktop f: gestures flutter/packages/flutter/gestures repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants