-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Add friction coefficient to InteractiveViewer #109443
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 (don't just cc him here, he won't see it! He's on Discord!). 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. |
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
spaces removed
| /// Changes the scrolling behavior after end of a gesture. | ||
| /// | ||
| /// Used as the coefficient of friction in the inertial translation animation. | ||
| /// This value was eyeballed to give a feel similar to Google Photos. | ||
| /// | ||
| /// Defaults to 0.0000135. | ||
| /// | ||
| /// Cannot be null, and must be a finite number greater than 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.
Can we add documentation on how the scroll changes when the value increases or decreases?
|
I agree with this change, it would be nice if the constant internal value could be changed. I think the solution is quite simple. Thanks for raising the PR! I just added small nit comments regarding naming and documentation, overall looks good to me. Are you planning to add tests? |
|
Thank you @alestiago! I can add some tests but first I have to look at the documentation what I have to do to add a test. It was my first PR. |
scrollFriction renamed to scrollFrictionCoefficient Co-authored-by: Alejandro Santiago <dev@alestiago.com>
rename scrollFriction
* added a test
|
I've added a test but I don't know what I should test exactly. That parameter is very random. |
spaces removed
|
You could test how the amount of scroll differs when a value x is provided compared to when a value y is given. |
justinmc
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.
Thanks for opening this PR, I'm on board but I want to make sure there's not a more generic way to solve this.
This makes me think of Scrollable's physics parameter. What if we allowed users to pass in the entire Simulation and defaulted to the current FrictionSimulation? Or even more high level, maybe InteractiveViewer should be using ScrollPhysics?
@Piinks You're working on 2D scrolling, are you using regular ScrollPhysics for that, or is there anything that could also apply here?
I'm not saying that scrollFrictionCoefficient isn't the best solution here, I just want to think through these other options.
|
I agree with @justinmc making use of a subclass of ScrollPhysics to achieve the effect is an interesting and more consistent solution with the framework and other Scrollables. Definitely a great suggestion! I'm also glad to hear @justinmc is onboard with the aims of this PR. Thanks for hopping in 💙 I'm curious about @Piinks insights and opinion on this PR to 👀 |
Piinks
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.
I would love to incorporate more scrolling into interactive viewer, but I think it is more complicated than adding some properties that emulate scrolling. I've been exploring this in #64210. Ultimately, under the hood InteractiveViewer is not a scrolling widget. We may be able to rework it to become one, but that may require breaking changes, which is why I have been working on a separate 2D scrollable that would avoid breaking existing code.
I don't think adding this is a bad idea, I would just avoid referring to it as scrolling.
| // use cases. | ||
| this.maxScale = 2.5, | ||
| this.minScale = 0.8, | ||
| this.scrollFrictionCoefficient = _kDefaultScrollFrictionCoefficient, |
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.
This feels a bit misleading, InteractiveViewer is not a scrolling widget. If we use scrolling terms, users expect other scrolling conventions to apply, like having a ScrollPosition, and ScrollNotifications.
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.
It's a good point. How about we call it interactionEndFrictionCoefficient or dragEndFrictionCoefficient?
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.
That sounds good to me! :)
@codeforce-dev is there an open issue that this is seeking to resolve? It would be very helpful in answering these questions and better understanding the request. |
|
The coefficient would be the simplest way to optimize the "scrolling" behaviour for some purposes. A more complex solution is not necessary. For example, pdf_render uses InterativeViewer to handle the user interaction. But in my opinion, the default drag behaviour with a value of 0.0000135 feels not good for that purpose. |
justinmc
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.
It sounds to me like a custom Simulation is too confusing and low-level for use cases like the one given by @codeforce-dev. I say let's just go forward with exposing the coefficent of friction like in this PR 👍.
A few comments below but I think this is almost ready. Thanks for dealing with all of my questions on making sure this is the best solution!
| // late TransformationController _transformationController; | ||
| // Widget child = const Placeholder(); | ||
|
|
||
| /// Default coefficient of friction. |
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 the original comments on _kDrag had some important details about where the value came from:
// Used as the coefficient of friction in the inertial translation animation.
// This value was eyeballed to give a feel similar to Google Photos.
| /// Used as the coefficient of friction in the inertial translation animation. | ||
| /// This value was eyeballed to give a feel similar to Google Photos. | ||
| /// | ||
| /// Defaults to [_kDefaultInteractionEndFrictionCoefficient]. |
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.
This constant is private. I think we should explicitly give the 0.0000135 value here, because readers will want to know whether to give a value greater than or less than that for their own use cases.
| await tester.dragFrom(const Offset(100.0, 100.0), const Offset(0.0, 50.0)); | ||
| final Vector3 translation2 = transformationController.value.getTranslation(); | ||
|
|
||
| expect(translation2.y, equals(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.
I think this isn't properly testing the feature. It looks like in the first drag, the expectation happens immediately after the drag, before any inertia animation has happened, so the y value is exactly the same as the length of the gesture (-50.0). In the second drag, it goes in the opposite direction and ends up not moving at all (because it hit the boundary?).
What if you pumpAndSettle after each drag and then get the translation? I imagine then you would see more translation because the inertia animation has happened. (And I think make sure the second drag goes in the same direction as the first.)
Lastly, I think the most important expectation is that translation1.y > translation2.y, because that shows that a greater coefficient of friction slows down the animation more quickly.
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.
Thanks for your reply. I've already tried dragFrom and moveBy with pumpAndSettle but unfortunately it has no effect on it. I always get -50.
final TestGesture gesture = await tester.startGesture(const Offset(100, 100));
await gesture.moveBy(const Offset(0, -50));
await tester.pumpAndSettle();
final Vector3 translation = transformationController.value.getTranslation();
// translation.y = -50;
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.
In that case, flingFrom is the solution.
await tester.flingFrom(const Offset(100, 100), const Offset(0, -50), 100.0);
await tester.pumpAndSettle();
_kDefaultInteractionEndFrictionCoefficient constant removed for more readability
Piinks
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 with a few nits - thank you!
| /// Changes the scrolling behavior after end of a gesture. | ||
| /// | ||
| /// Used as the coefficient of friction in the inertial translation animation. | ||
| /// This value was eyeballed to give a feel similar to Google Photos. |
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 remove this? This could change at any time, but also does not account for how Google Photos behaves on different devices.
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.
+1. Keep it in the comments below, but remove it from the public docs. You could make it "Google Photos on Android 12" since I think that's what I was using when I wrote that comment.
justinmc
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 with nits as well. Let me know if you want to fix those and we can get this merged. 👍
| /// Changes the scrolling behavior after end of a gesture. | ||
| /// | ||
| /// Used as the coefficient of friction in the inertial translation animation. | ||
| /// This value was eyeballed to give a feel similar to Google Photos. |
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.
+1. Keep it in the comments below, but remove it from the public docs. You could make it "Google Photos on Android 12" since I think that's what I was using when I wrote that comment.
| MaterialApp( | ||
| home: Scaffold( | ||
| body: SizedBox( | ||
| width: 200, height: 200, |
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.
Separate these onto different lines.
| await tester.pumpAndSettle(); | ||
| final Vector3 translation2 = transformationController2.value.getTranslation(); | ||
|
|
||
| // Test 2 movement must be greater than in Test 1. |
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.
Change this to: The coefficient 0.01 is greater than the default of 0.0000135, so the translation comes to a stop more quickly.
|
Hi @codeforce-dev, would you like to address the outstanding comments from @justinmc so this can land? Thanks! |


It would be nice if the kDrag parameter were public to change the scrolling behavior.
For example I've changed the kDrag var into a public parameter called scrollFriction.
Pre-launch Checklist
///).