-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Update ClampingScrollSimulation to better match Android #77497
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
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
|
I created a diff between the output |
| return 9.80665 * | ||
| 39.37 * | ||
| friction * | ||
| 1.0 * // Assume display density of 1.0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how much of a difference does this make? if it matters, we should be able to find a way to get the pixel density here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an API in Android but I couldn't find one in Flutter. We have deviceRatio which is slightly different. For what it's worth, this hasn't changed from the previous logic, just the formula is now explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
although, actually, maybe 1.0 is the right number here? since we operate in logical pixels not physical pixels in the framework. In which case the comment should reflect that -- it's not an assumption, it's a reality.
| _splineTime[i] = coef * ((1.0 - y) * p1 + y * p2) + y * y * y; | ||
| } | ||
| _splinePosition[_nbSamples] = _splineTime[_nbSamples] = 1.0; | ||
| _isInitialized = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we do this statically and just fill in the data? (rather than doing it at runtime on first use)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean statically through code, like in the JAVA implementation? If so, no I don't think Dart offers anything similar hence the somewhat awkward implementation.
If you actually meant writing an external program to create the static data, we could do that. It would obviously not be as easily configured liked the Android implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no "static initialization" time in Dart. All code that runs should do so as a result of invoking main().
The options here are either to compute it on first use, or to add a hook somewhere in the framework to cause it to be computed early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant offline (as in have a program in the dev/ directory that runs this code and generates the constants and you can just paste them into this file). Looks like this code isn't configurable by developers, so that wouldn't reduce the overall configurability for our developers, but would be more efficient for users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| /// Creates a scroll physics simulation that matches Android scrolling. | ||
| ClampingScrollSimulation({ | ||
| required this.position, | ||
| required this.velocity, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the "some simplifications have been made" bit still true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The logic in Scroller.java is 2-dimensional and has logic for non "fling" scrolls so there are simplifications still.
|
what's the performance like? |
|
I'll defer to @HansMuller or @goderbauer for a detailed review. |
|
Removed the unnecessary diffs.
Performance should be more or less equivalent after the spline data is initialized as there are roughly the same number of operations. I doubt the initialization has a measurable impact on the performance but it'd be good to know how best to verify that assumption. |
| }); | ||
|
|
||
|
|
||
| test('ClampingScrollSimulation velocity eventually reaches zero', () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note these new tests fail with the old logic. As noted in the my previous comment, velocity ramps back up near the end of the simulation.
goderbauer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like some existing tests are failing. Did you take a look at those?
| import 'dart:math' as math; | ||
|
|
||
| import 'package:flutter/foundation.dart'; | ||
| import 'package:flutter/material.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
files in the widgets directory can't import material.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was an artifact of getting the deviceRatio in a pervious implementation. I'm surprised there isn't an unused import lint or issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(material reexports most of widgets so it doesn't get flagged as unused. redundant imports is a lint we haven't deployed yet though I understand work is ongoing.)
|
This should be ready for review PTAL. |
|
Looks like there are still some test failures. |
| const double _endTension = 1.0; | ||
| const double _inflexion = 0.35; | ||
|
|
||
| // Generated spline data used in ClampingScrollSimulation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a little more context to this doc? E.g. where's the math in here coming from? What should be done with the result after changing anything here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| } | ||
| } | ||
|
|
||
| class _NBSample { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does the NB stand for? Maybe document or just spell it out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I'm not sure. I think it might just happen to be the variable name of choice for the underlying math equation that the original developer likely referenced. I kept it here as I wanted it to be immediately obvious how this logic is translated from Scroller.java.
|
|
||
| static const int _nbSamples = 100; | ||
|
|
||
| // Generated from dev/tools/generate_android_spline_data.dart. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, we would have some kind of a test to verify that the numbers reproduced here match the result of that calculation to ensure that we update things here if the calculation math ever changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A test may be helpful but I don't think it provides a ton of value. Updating the comment in the file as you suggested should make things much more clear.
|
Overall, this looks good. Thanks for taking the time to update it! I am going to trigger a google3 presubmit to see if it breaks any tests there (like it broke some of our framework tests). |
goderbauer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
| find.byType(ListWheelScrollView), | ||
| const Offset(0.0, -50.0), | ||
| 800.0, | ||
| 100.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grouma Can you recall why this fling needed to be reduced so much? This is probably the same regression that has been reported for flings going way too far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I do not. I recall that a number of tests had to have their parameters updated to keep the "goldens" valid. The main intent behind this change was to fix the jitter users would experience as the scroll slowed down. I added a test for that invalid behavior, see ClampingScrollSimulation velocity eventually reaches zero.
|
Chatted with @goderbauer and we are going to revert this, unfortunately it has been in for a while so it can't be done automatically. I should be able to do this manually tomorrow and add some extra tests while I am at it. |
I've noticed that the Android Flutter scroll logic appears to be slightly off. After a scroll slows down to a sufficient amount, items appear to "snap" into place. It's as if the inertial scrolling clamps down and micro movements are not allowed. Note the difference is very subtle but present across Flutter apps, e.g. Stadia, gPay etc. It appears that the underlying implementation is an approximation of the Android logic which may explain the behavior.
Since this has been driving me mad I have decided to translate the 2-dimensional logic from Scroller.java to 1 dimension and reuse in Flutter. The behavior should now be identical assuming equivalent DPI and friction settings.