Repository navigation
Scroll physics on iOS is excessively damped #32448
Description
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
xster commentedon May 10, 2019
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?
matthewlloyd commentedon May 10, 2019
Done, that was very instructive. Here's what I found (all this applies to iOS only). I'm on the master channel.
scroll_overlayapp. However it's much slower in my own app (without me making any changes).scroll_overlay,createBallisticSimulationis called only twice per fling, once at the start and once at the end. In my own app, which contains aListViewof a few hundredRowsof varying heights,createBallisticSimulationis 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.scroll_overlayapp, 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:
0.91constant. 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 oftencreateBallisticSimulationis getting called, since that seems to depend on what's inside the scroll view and whether it's changing.createBallisticSimulationrepeatedly during the fling gesture. It seems unnecessary to instantiate a completely new simulation just because themaxScrollExtenthas changed from (in my case) 2090 to 2090.25. These repeated calls are coming from calls toScrollPosition.applyNewDimensions.saurik commentedon Aug 22, 2019
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).
saurik commentedon Aug 22, 2019
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.
justinmc commentedon Aug 22, 2019
@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!
Reduce damping in iOS scrollbehavior for list with differently sized …
[scroll_overlay] Use different sized items (#2)
github-actions commentedon Aug 18, 2021
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 -vand a minimal reproduction of the issue.