Skip to content
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

Scrolling with two fingers scrolls twice as fast #11884

Closed
goderbauer opened this issue Aug 31, 2017 · 35 comments · Fixed by #136708
Closed

Scrolling with two fingers scrolls twice as fast #11884

goderbauer opened this issue Aug 31, 2017 · 35 comments · Fixed by #136708
Assignees
Labels
customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: gestures flutter/packages/flutter/gestures repository. f: scrolling Viewports, list views, slivers, etc. found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list r: fixed Issue is closed as already fixed in a newer version team-framework Owned by Framework team triaged-framework Triaged by Framework team

Comments

@goderbauer
Copy link
Member

When scrolling a Flutter list with two fingers the list scrolls twice as fast.

In native Android or iOS apps, the list continues to scroll in regular speed even with two fingers.

Note: This is NOT specific to accessibility scrolling with two fingers. It's visible even when accessibility is disabled. However, it's also a problem for accessibility scrolling, where using two fingers are commonly used for scrolling.

@goderbauer goderbauer added the f: scrolling Viewports, list views, slivers, etc. label Aug 31, 2017
@eseidelGoogle eseidelGoogle added the framework flutter/packages/flutter repository. See also f: labels. label Sep 1, 2017
@eseidelGoogle
Copy link
Contributor

While this is awesome, I suspect this will block AX work and we should remove it. :)

@tevjef
Copy link

tevjef commented Sep 22, 2018

The scrolling speed increases with the number of fingers on screen.

@zoechi zoechi added this to the Goals milestone Sep 23, 2018
@wanjm
Copy link

wanjm commented Oct 18, 2019

I still come across with such problem with 1.9.1 +hotfix4 & 5;
any progress on this?

@VladyslavBondarenko
Copy link

VladyslavBondarenko commented Mar 27, 2020

Still persists (master v1.16.3-pre.56)

checked with that simple code
import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: MyApp(),));

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: List.generate(100, (index) => ListTile(
          title: Text(index.toString()),
        )),
      ),
    );
  }
}

The scrolling speed increases according to the number of fingers on screen.

@VladyslavBondarenko VladyslavBondarenko added has reproducible steps The issue has been confirmed reproducible and is ready to work on f: gestures flutter/packages/flutter/gestures repository. labels Mar 27, 2020
@dkwingsmt
Copy link
Contributor

Part of: #38926

@VladyslavBondarenko
Copy link

Persists with current master 1.21.0-6.0.pre.38

flutter doctor -v
[✓] Flutter (Channel master, 1.21.0-6.0.pre.38, on Mac OS X 10.15.6 19G73, locale en-GB)
    • Flutter version 1.21.0-6.0.pre.38 at /Users/nevercode/dev/flutter
    • Framework revision 8e0eee9008 (5 hours ago), 2020-07-26 23:38:01 -0700
    • Engine revision 626244a72c
    • Dart version 2.9.0 (build 2.9.0-21.0.dev a3815b6590)
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    • Android SDK at /Users/nevercode/Library/Android/sdk
    • Platform android-29, build-tools 29.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.6, Build version 11E708
    • CocoaPods version 1.9.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 47.1.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] VS Code (version 1.47.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.12.2

[✓] Connected device (5 available)
    • Redmi Note 7 (mobile)       • 6345c469                                 • android-arm64  • Android 9 (API 28)
    • Nevercode’s iPhone (mobile) • b668e524315069f3db3661ac11ff1f66afafebdb • ios            • iOS 13.6
    • macOS (desktop)             • macos                                    • darwin-x64     • Mac OS X 10.15.6 19G73
    • Web Server (web)            • web-server                               • web-javascript • Flutter Tools
    • Chrome (web)                • chrome                                   • web-javascript • Google Chrome 84.0.4147.89

• No issues found!

@VladyslavBondarenko VladyslavBondarenko added the found in release: 1.21 Found to occur in 1.21 label Jul 27, 2020
@Hixie Hixie removed this from the None. milestone Aug 17, 2020
@fzyzcjy
Copy link
Contributor

fzyzcjy commented Oct 6, 2020

I find a workaround for it! :D

Please look at this question (answered by myself after digging into flutter source code).

Note: Do not worry about that question's title. If you set onlyScrollableWhenMultiFinger: true inside my sample shown there, you will solve this question, without disabling single finger scrolling.

@adschi
Copy link

adschi commented Nov 24, 2020

Any solution for the whole app to disable that feature?

@RandalSchwartz
Copy link

Can we leave something like this in there though? It's a great shibboleth to detect Flutter apps in the wild.

@jmshrv
Copy link

jmshrv commented Jul 31, 2022

There are plenty of ways to tell whether or not an app uses Flutter, I'm sure we can fix this one 🙃

@RandalSchwartz
Copy link

There are plenty of ways to tell whether or not an app uses Flutter, I'm sure we can fix this one 🙃

Like?

@jmshrv
Copy link

jmshrv commented Aug 21, 2022

Off the top of my head:

  • On iOS, the scrollbar stops when you try to flick it. In native iOS apps, the scrollbar keeps momentum after you let go
  • The inkwell effect in Material buttons fills slowly. In native Android apps, it fills within ~0.25 seconds
  • On iOS, holding down the back button doesn't show the list of previous pages (I haven't tested this with CupertinoApp so apologies if it works there)
  • When scrolling a ScrollView that isn't big enough to actually scroll, the overflow effect will show in Android

@alxlion
Copy link

alxlion commented Mar 6, 2023

There are plenty of ways to tell whether or not an app uses Flutter, I'm sure we can fix this one 🙃

Like?

Like FlutterHunt I think

@valorbyte
Copy link

I don't mind this for one-dimensional lists, but this "feature" does bring some issues to pinch-zoom + scroll, which works flawlessly on native iOS but very weirdly in Flutter since the scroll speed is doubled.

@alxlion
Copy link

alxlion commented Mar 8, 2023

I'm trying to solve this issue, not easy but I found this:
flutter/lib/src/gestures/monodrag.dart:274

@override
  bool isPointerAllowed(PointerEvent event) {
    if (_initialButtons == null) {
      if (onDown == null && onStart == null && onUpdate == null && onEnd == null && onCancel == null) {
        return false;
      }
    } else {
      // There can be multiple drags simultaneously. Their effects are combined.
      if (event.buttons != _initialButtons) {
        return false;
      }
    }
    return super.isPointerAllowed(event as PointerDownEvent);
  }

There can be multiple drags simultaneously. Their effects are combined.

It seems to be a normal behavior, but why ?

@darshankawar darshankawar added found in release: 3.9 Found to occur in 3.9 and removed found in release: 1.21 Found to occur in 1.21 labels Mar 9, 2023
@hitiksaini
Copy link

hitiksaini commented May 25, 2023

This can be left unsolved(only if this doesn't break things elsewhere).
Normally, I use it as a quick way to check if an app is using flutter 😄

@JanHitako
Copy link

@hitiksaini This does break the user experience in a common use case though.

How?
If you have 2 or more fingers scrolling in opposite directions, they sort of cancel each other out but not quite, ending in some sort of janky movement going either direction.

The issue
The issue is that, and this is rather apparent on low to low-medium-range phones I have tested with rounded edges or borderless screens, the palm of the hand is mistaken by the device as a single or many fingers, therefore during one-hand use of a device, the palm of the hand touching the border of the screen interfere with the actual scroll of the user, sometimes not by much (slowing down the actual scroll "randomly"), sometimes quite badly. Even when it is minimal, it is noticeable enough to break the experience.

Medium and higher-end phones do not seem to have this issue with hand palms however this still should be fixed so as to not alienate an entire market.

@flutter-triage-bot flutter-triage-bot bot added team-framework Owned by Framework team triaged-framework Triaged by Framework team labels Jul 8, 2023
@hitiksaini
Copy link

@hitiksaini This does break the user experience in a common use case though.

How? If you have 2 or more fingers scrolling in opposite directions, they sort of cancel each other out but not quite, ending in some sort of janky movement going either direction.

The issue The issue is that, and this is rather apparent on low to low-medium-range phones I have tested with rounded edges or borderless screens, the palm of the hand is mistaken by the device as a single or many fingers, therefore during one-hand use of a device, the palm of the hand touching the border of the screen interfere with the actual scroll of the user, sometimes not by much (slowing down the actual scroll "randomly"), sometimes quite badly. Even when it is minimal, it is noticeable enough to break the experience.

Medium and higher-end phones do not seem to have this issue with hand palms however this still should be fixed so as to not alienate an entire market.

@JanFeni I understand your point of view. I haven't got my hands on with low-end phones. Thanks for this information.

@milindgoel15
Copy link

It could become an optional feature tho. Like making a Boolean at the top level say MaterialApp (in case of android) as enableTwoFingerFastScroll or something and keeping it off by default.

@definev
Copy link

definev commented Oct 4, 2023

This issues is dramatically affecting to many app that have Tiktok-like vertical video, if user scrolling using 2 finger it will unconditionally move faster so very bad UX

@xu-baolin
Copy link
Member

Hahahaha, so interesting

@2p31-1

This comment was marked as duplicate.

@JacobSyndeo
Copy link

JacobSyndeo commented Nov 15, 2023

Touching (ha) on @gnprice's comment regarding scroll behavior, Apple platforms average the motion of all fingers, rather than summing them.

Try scrolling with two fingers, then leaving one in place while continuing to move the second. You'll notice the motion is now halved. Now pause the one that you kept moving and moved the first one in the other direction. You'll see it moves back at half speed as well. Now move both fingers towards each other, and then back apart again; you shouldn't see much scroll motion at all.

It essentially creates a virtual scroll "touch" at the average/midpoint between the two fingers. And I believe that this implementation that would be a great solution here as well, at least when targeting Apple platforms.

EDIT: @goderbauer pointed out that iOS actually uses a different algorithm now, which I'll take a stab at implementing.

As Android's behavior differs, listening only to the most recent touch, I believe Flutter should do the same when targeting Android.

There's definitely something to be said for having consistent behavior across platforms (and this is one of Flutter's strengths), but scrolling feels like such a fundamental part of the UX that I believe it should be tailored to each platform's stock behavior by default.

But in the spirit of full customization, (while this runs counter to good UX IMO), if certain developers really want to set a specific behavior across their app regardless of platform, we can expose this as an enum option.

Something like this:

enum MultiTouchScrollBehavior { platformDefault, average, first, last, sum }

Where platformDefault uses average for Apple platforms and last for Android. We could add first for new behavior, but I'm not certain of the value. Finally, sum would be the current existing behavior.

Whether or not we want to leave existing projects on sum or default them to platformDefault moving forward is another discussion, IMO.

Thoughts? I'd be willing to try to build this out for proposal if folks are interested.

EDIT: PR open here: #138763

@goderbauer
Copy link
Member Author

Try scrolling with two fingers, then leaving one in place while continuing to move the second. You'll notice the motion is now halved. Now pause the one that you kept moving and moved the first one in the other direction.

I tried this in a number of Apple apps on iOS 17 (e.g. the App Store and the Settings app) and wasn't able to see this behavior.

but scrolling feels like such a fundamental part of the UX that I believe it should be tailored to each platform's stock behavior by default.

Yes, our goal is to be as close as possible to the "native" behavior to not disrupt a user's muscle memory.

@JacobSyndeo
Copy link

JacobSyndeo commented Nov 20, 2023

Wow, would you look at that… I feel like I'm in the twilight zone or something, because I could've sworn that's how it worked. (Perhaps it worked this way in the past? In any case, let's only focus on what current versions do.)

In any case, I stand corrected; thanks for pointing that out, @goderbauer.

(Unfortunate, too… I was just now opening a PR that included a behavior fix for both iOS and Android, with Android using the last-touch behavior based on @xu-baolin's solution, and iOS using the averaging behavior I thought it had. I'll have to refactor the latter!)

Anyway, at a glance, iOS' actual algorithm appears to be more complicated.
If multiple fingers are onscreen at a time, it'll listen fully to (and thus fully track) whichever one you move:

IMG_2271-480.mov

Also key, of course, is that moving two fingers together tracks the fingers' midpoint, which is essentially the averaging behavior I mentioned earlier. You can confirm this by dragging two fingers along the screen, but having one start moving faster than the other one. However, if one of the two moving fingers stops moving, the system reverts to fully tracking the one that's actively moving.

Essentially, for iOS, it seems like we need to consider moving fingers as "active" participants, and average their position and motion. But when they're no longer moving (perhaps their motion delta per-frame is below a certain threshold), they're to be considered "inactive", and thus exempt from the averaging.

IMG_2273-480.mov

There is, however, a baffling quirk… if at any point a finger is lifted, the remaining fingers seem to sometimes be forcefully rendered "inactive" by iOS, and will be entirely ignored for the remainder of their time in contact with the display. But I don't know that we need to worry about nor replicate this level of nuance, as I'm not sure it's even intentional due to its apparent coin-flip nature. If anyone can see a pattern in this behavior, please let me know. It seems to exist to facilitate "fling" scrolling even if the user accidentally has another finger sitting onscreen, but I'm unsure.

I'll modify my solution in light of this, sans implementing the quirk for now.

auto-submit bot pushed a commit that referenced this issue Nov 30, 2023
…36708)

Fixes #11884

As #38926 pointed out, the current Flutter implementation of multi-finger drag behavior is different from iOS and Android.
This change introduces the `MultitouchDragStrategy` attribute, which implements the Android behavior and can be controlled through `ScrollBehavior`, while retaining the ability to extend iOS behavior in the future.
@darshankawar darshankawar added the r: fixed Issue is closed as already fixed in a newer version label Dec 1, 2023
@simonpham
Copy link

It's time guys. We can no longer check if an app is written in Flutter using this scrolling behaviour.

@squirelboy360

This comment was marked as off-topic.

@jmshrv
Copy link

jmshrv commented Dec 8, 2023

Take a look at the PR - MultiTouchDragBehavior.sum is available if you wanted the old scrolling for some reason. The Flutter docs has an interesting page on how it adapts to the platform if you're interested.

@squirelboy360

This comment was marked as off-topic.

@esentis

This comment was marked as outdated.

Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 23, 2023
caseycrogers pushed a commit to caseycrogers/flutter that referenced this issue Dec 29, 2023
…utter#136708)

Fixes flutter#11884

As flutter#38926 pointed out, the current Flutter implementation of multi-finger drag behavior is different from iOS and Android.
This change introduces the `MultitouchDragStrategy` attribute, which implements the Android behavior and can be controlled through `ScrollBehavior`, while retaining the ability to extend iOS behavior in the future.
@gnprice
Copy link
Member

gnprice commented Jan 4, 2024

For the sake of making the outcome visible explicitly on this thread: the current solution is that the default behavior on all platforms is that the latest finger controls the scrolling. That's the same as the Android native behavior, as described at #11884 (comment).

See #136708 which made the fix, and the docs at:
https://main-api.flutter.dev/flutter/gestures/DragGestureRecognizer/multitouchDragStrategy.html
https://main-api.flutter.dev/flutter/gestures/MultitouchDragStrategy.html

(I figured this was worth clarifying here because the latest discussion above was toward a different option, where we'd also implement the iOS native behavior and make that the default on iOS. That may still happen in the future if there's a desire for it, but it'd be its own issue.)

Very happy this is fixed! Thanks @xu-baolin @JacobSyndeo and everyone else who contributed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: gestures flutter/packages/flutter/gestures repository. f: scrolling Viewports, list views, slivers, etc. found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list r: fixed Issue is closed as already fixed in a newer version team-framework Owned by Framework team triaged-framework Triaged by Framework team
Projects
None yet