Skip to content

Scrolling with two fingers scrolls twice as fast #11884

Description

@goderbauer

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.

Activity

  1. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Sep 1, 2017
  2. eseidelGoogle commented on Sep 1, 2017

    @eseidelGoogle
    Contributor

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

  3. tevjef commented on Sep 22, 2018

    @tevjef

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

  4. added this to the milestone on Sep 23, 2018
  5. wanjm commented on Oct 18, 2019

    @wanjm

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

  6. VladyslavBondarenko commented on Mar 27, 2020

    @VladyslavBondarenko

    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.

  7. added
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    f: gesturesflutter/packages/flutter/gestures repository.
    on Mar 27, 2020
  8. dkwingsmt commented on Mar 27, 2020

    @dkwingsmt
    Contributor

    Part of: #38926

  9. added
    P2Important issues not at the top of the work list
    on May 29, 2020
  10. VladyslavBondarenko commented on Jul 27, 2020

    @VladyslavBondarenko

    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!
    
  11. removed this from the milestone on Aug 17, 2020
  12. fzyzcjy commented on Oct 6, 2020

    @fzyzcjy
    Contributor

    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.

  13. 25 remaining items

  14. JacobSyndeo commented on Nov 15, 2023

    @JacobSyndeo

    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

  15. goderbauer commented on Nov 20, 2023

    @goderbauer
    MemberAuthor

    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.

  16. JacobSyndeo commented on Nov 20, 2023

    @JacobSyndeo

    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.

  17. added a commit that references this issue on Nov 30, 2023
    d49dcaa
  18. added
    r: fixedIssue is closed as already fixed in a newer version
    on Dec 1, 2023
  19. simonpham commented on Dec 4, 2023

    @simonpham
    Contributor

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

  20. squirelboy360 commented on Dec 8, 2023

    @squirelboy360
  21. UnicornsOnLSD commented on Dec 8, 2023

    @UnicornsOnLSD

    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.

  22. squirelboy360 commented on Dec 8, 2023

    @squirelboy360
  23. esentis commented on Dec 9, 2023

    @esentis
  24. github-actions commented on Dec 23, 2023

    @github-actions

    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.

  25. locked as resolved and limited conversation to collaborators on Dec 23, 2023
  26. added a commit that references this issue on Dec 29, 2023
    bc7630d
  27. gnprice commented on Jan 4, 2024

    @gnprice
    Member

    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 join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listcustomer: crowdAffects or could affect many people, though not necessarily a specific customer.f: gesturesflutter/packages/flutter/gestures repository.f: scrollingViewports, list views, slivers, etc.found in release: 3.7Found to occur in 3.7found in release: 3.9Found to occur in 3.9frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions