Skip to content

Scroll physics on iOS is excessively damped #32448

Closed

Description

@matthewlloyd

I have a complex ListView with approximately 300 rows, and scrolling is demonstrating too much friction compared to a native list view on iOS. After some debugging, I figured out that it's because of this line in scroll_physics.dart:

velocity: velocity * 0.91, // TODO(abarth): We should move this constant closer to the drag end.

The createBallisticSimulation method seems to get called several times per second during the ballistic part of scroll movements on my ListView, which I think is because the ScrollMetrics.maxScrollExtent property is changing slightly as Flutter discovers the rendered sizes of the widgets as they scroll into the viewport. However, each time it gets called, the velocity gets scaled down by 0.91, which effectively adds a lot of additional friction to the otherwise quite smooth BouncingScrollSimulation.

I've worked around the issue by making my own ScrollPhysics class which changes the constant to 1.0 (i.e. no multiplication), and it works great, but it would be nice to have it fixed in the framework.

@override
  Simulation createBallisticSimulation(ScrollMetrics position, double velocity) {
    final Tolerance tolerance = this.tolerance;
    if (velocity.abs() >= tolerance.velocity || position.outOfRange) {
      return BouncingScrollSimulation(
        spring: spring,
        position: position.pixels,
        velocity: velocity * 0.91, // TODO(abarth): We should move this constant closer to the drag end.
        leadingExtent: position.minScrollExtent,
        trailingExtent: position.maxScrollExtent,
        tolerance: tolerance,
      );
    }
    return null;
  }

Steps to Reproduce

Scroll any reasonably complex ListView on iOS and observe that the physics
seem to be excessively damped compared to native iOS list views.

[✓] Flutter (Channel master, v1.5.9-pre.193, on Mac OS X 10.14.4 18E226, locale en-US)
    • Flutter version 1.5.9-pre.193 at /Users/mil/flutter
    • Framework revision 3a6acb8c25 (8 hours ago), 2019-05-09 09:23:30 -0700
    • Engine revision 644db5a49c
    • Dart version 2.3.1 (build 2.3.1-dev.0.0 a0290f823c)


[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/mil/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.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_152-release-1343-b01)
    • All Android licenses accepted.

[✓] iOS toolchain - develop for iOS devices (Xcode 10.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.2.1, Build version 10E1001
    • ios-deploy 1.9.4
    • CocoaPods version 1.6.0

[✓] Android Studio (version 3.4)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 35.2.1
    • Dart plugin version 183.6270
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)

[✓] IntelliJ IDEA Community Edition (version 2019.1.2)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 35.3.3
    • Dart plugin version 191.7141.49

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

Activity

  1. added
    a: fidelityMatching the OEM platforms better
    frameworkflutter/packages/flutter repository. See also f: labels.
    p: cupertino_uicupertino_ui package in flutter/packages
    f: scrollingViewports, list views, slivers, etc.
    on May 10, 2019
  2. xster commented on May 10, 2019

    @xster
    Member

    Do you mind running your tweaked value through https://github.com/flutter/platform_tests/tree/master/scroll_overlay to see if it matches the platform physics better?

  3. matthewlloyd commented on May 10, 2019

    @matthewlloyd
    ContributorAuthor

    Done, that was very instructive. Here's what I found (all this applies to iOS only). I'm on the master channel.

    • Currently, by default, with no changes, Flutter scrolling after a fling gesture is about 10% faster than the native iOS view, but otherwise matches almost perfectly in the context of the scroll_overlay app. However it's much slower in my own app (without me making any changes).
    • The reason is that in scroll_overlay, createBallisticSimulation is called only twice per fling, once at the start and once at the end. In my own app, which contains a ListView of a few hundred Rows of varying heights, createBallisticSimulation is being called multiple times per second during the fling (even with no user input). Each time the velocity gets reduced by ~10% by the line above.
    • If I apply the tweaked value to the scroll_overlay app, scrolling becomes about 20% faster than the native iOS view, i.e. worse. However, it fixes the issue in my own app.

    I think the solution to this problem would be to either:

    1. Eliminate the 0.91 constant. If the purpose is to reduce fling gesture velocity to match iOS, this needs to be implemented in a different place so that it only happens once at the start of the gesture. Perhaps it's not needed at all. Either way, fling gesture drag should not depend on how often createBallisticSimulation is getting called, since that seems to depend on what's inside the scroll view and whether it's changing.
    2. Find a way to avoid calling createBallisticSimulation repeatedly during the fling gesture. It seems unnecessary to instantiate a completely new simulation just because the maxScrollExtent has changed from (in my case) 2090 to 2090.25. These repeated calls are coming from calls to ScrollPosition.applyNewDimensions.
  4. saurik commented on Aug 22, 2019

    @saurik
    Contributor

    I just want to leave a comment here saying that we had to apply this workaround in our app. Given how much marketing Flutter does in the claim of "we have spent the time to make sure that Flutter apps feel native by even having written a tool to compare scroll velocity to native scroll velocity", the fact that one of the first things we ran into was "the scroll physics on this panel doesn't feel anything at all like a native iOS scroller" and we had to turn to issues to find a workaround for what is not just a bug but a documented TODO comment in the code base was extremely disappointing (though, at this point in our development, sadly already not surprising).

  5. saurik commented on Aug 22, 2019

    @saurik
    Contributor

    So, one of my co-workers decided to poke me and say I was being harsh, that """I would not be surprised if someone posts it on Twitter as an example of "this developer doesn't value our time and is bothering us on our issue tracker"""". FWIW, I'm sorry if that is how I'm coming across. I would point out that I'm quite often the person who defends developers dealing with limited time and a pile of bugs and I go out of my way to upstream all of the ancillary patches I make to project dependencies. FWIW, I attended the Flutter Live viewing in Mountain View late last year in person to talk to engineers about the prioritization of issues I had been poking at, rather than trying to be some impersonal face on an issue tracker (and also provided some feedback on the build system).

    What I'm trying to accomplish here is that I know Flutter is only prioritizing bugs based on customer feedback, and I think the emotional reaction I experience to "all of the marketing material touts this one specific feature" is highly relevant, as it starts to cross the line into "disingenuous". When our UI engineer pointed me at this bug as the reason for the problem, I even remembered this bug, as I had seen it crop up in a discussion a month ago about some big Flutter exposé article. Given how simple our app UI currently is and how we are already running into this, and how this was a titular feature that I believe I even remember being demoed on stage (whether at Flutter Live or I/O), it seems likely that the vast majority of potential Flutter users are also running into this same moment.

    Regardless, if the issue is that it just isn't clear where to put that line of code (which maybe will require some massive refactor), I'd also be happy to spend the time to provide a clean pull request for this issue.

  6. justinmc commented on Aug 22, 2019

    @justinmc
    Contributor

    @saurik I really appreciate all of the above, from the feedback and criticism to the thoughtfulness in your follow up. Obviously everyone actively contributing to Flutter right now is being pulled in many directions at once, but we rely on our community to find imperfections like this and to let us know how much of a problem they're causing. Feedback like this is really valuable while we work to make Flutter better.

    If you have time to write up that pull request, I would be happy to do the code review and help get it merged!

  7. added
    customer: crowdAffects or could affect many people, though not necessarily a specific customer.
    on Feb 26, 2020
  8. github-actions commented on Aug 18, 2021

    @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.

  9. locked as resolved and limited conversation to collaborators on Aug 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: fidelityMatching the OEM platforms bettercustomer: crowdAffects or could affect many people, though not necessarily a specific customer.f: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.p: cupertino_uicupertino_ui package in flutter/packages

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions