这是indexloc提供的服务,不要输入任何密码
Skip to content

fix cupertino page route dismisses hero transition when swipe to the … #58024

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

Merged
merged 3 commits into from
Jun 5, 2020

Conversation

chunhtai
Copy link
Contributor

@chunhtai chunhtai commented May 26, 2020

…edge

Description

When doing cupertino back swipe, the page animation will be dismissed/completed when the gesture reach either end of the screen. This will cause the hero controller to remove the overlay entry of the flighting hero. If the user keep holding the finger and swipe, the hero animation will not respond because it is no longer in the overlay

Related Issues

Fixes #57581

Tests

I added the following tests:

See files

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

  • No, no existing tests failed, so this is not a breaking change.
  • Yes, this is a breaking change. If not, delete the remainder of this section.
    • I wrote a design doc: https://flutter.dev/go/template Replace this with a link to your design doc's short link
    • I got input from the developer relations team, specifically from: Replace with the names of who gave advice
    • I wrote a migration guide: Replace with a link to your migration guide

@fluttergithubbot fluttergithubbot added f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels May 26, 2020
@chunhtai chunhtai added the c: API break Backwards-incompatible API changes label May 26, 2020
@@ -633,7 +636,8 @@ class _CupertinoBackGestureController<T> {
/// The drag gesture has changed by [fractionalDelta]. The total range of the
/// drag should be 0.0 to 1.0.
void dragUpdate(double delta) {
controller.value -= delta;
final double newValue = controller.value - delta;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this solution. Ideally the animation should be smart enough to not send animation status update when there is an ongoing gesture. However, I can't think of a good way to do it because the animation is provided from TransitionRoute and we also need to send animation status update when the gesture is lifted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the clamp prevents the animation from finishing by keeping its value between 0.0 and 1.0? I can't think of a better approach off the top of my head...

@chunhtai chunhtai requested review from goderbauer, xster and justinmc May 26, 2020 17:51
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some nits.

@@ -37,6 +37,9 @@ const Color _kModalBarrierColor = CupertinoDynamicColor.withBrightness(
// The duration of the transition used when a modal popup is shown.
const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335);

const double _kdragingAnimationUpperLimit = 0.998;
const double _kdragingAnimationLowerLimit = 0.002;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The letter after _k should be capitalized for these two, and dragging should have two letter g's.

Also maybe add a comment about where these values came from, like whether they're just what felt right to you, or if they were calculated somehow, etc.

await tester.pump();
await tester.pump(const Duration(milliseconds: 50));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could pumpAndSettle work here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for two other cases below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to make sure the ballistic scroll is small enough that can be neglect by human eyes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, sounds good.

@@ -633,7 +636,8 @@ class _CupertinoBackGestureController<T> {
/// The drag gesture has changed by [fractionalDelta]. The total range of the
/// drag should be 0.0 to 1.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment about 0.0-1.0 still accurate with the changes?

@@ -633,7 +636,8 @@ class _CupertinoBackGestureController<T> {
/// The drag gesture has changed by [fractionalDelta]. The total range of the
/// drag should be 0.0 to 1.0.
void dragUpdate(double delta) {
controller.value -= delta;
final double newValue = controller.value - delta;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the clamp prevents the animation from finishing by keeping its value between 0.0 and 1.0? I can't think of a better approach off the top of my head...

Copy link
Member

@xster xster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's triggering the removal of the hero overlay? Is the HorizontalDragGestureRecognizer calling onEnd somehow?

await tester.pump();
await tester.pump(const Duration(milliseconds: 50));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this causes the side effect that there will always be a ballistic scroll at the end of a drag no matter where we dropped it off?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I try to update the test to make sure it just requires a small pump to finish the ballistic scroll that can be neglected by human eyes

@@ -1133,6 +1133,76 @@ void main() {
expect(nestedObserver.popupCount, 0);
});

testWidgets('showCupertinoModalPopup uses root navigator by default', (WidgetTester tester) async {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this description right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no its not, thanks for catching it

@chunhtai
Copy link
Contributor Author

What's triggering the removal of the hero overlay? Is the HorizontalDragGestureRecognizer calling onEnd somehow?

It trigger removal when the animation status become dismissed or completed. The animation of the route is AnimationController, that it will update its status to dismissed if its value reach 0 or completed if reach 1.0

void _internalSetValue(double newValue) {

@xster
Copy link
Member

xster commented May 28, 2020

ah ya, that's unfortunate. Looks like native iOS allows for the page to be fully swiped to the edge then back too.

Changing the whole animation controller behavior is probably too big of a change. What about making use of navigator didStartUserGesture and somehow not hooking the animation status listener until the gesture stopped?

@chunhtai
Copy link
Contributor Author

ah ya, that's unfortunate. Looks like native iOS allows for the page to be fully swiped to the edge then back too.

Changing the whole animation controller behavior is probably too big of a change. What about making use of navigator didStartUserGesture and somehow not hooking the animation status listener until the gesture stopped?

thank you. I think i found a better solution and avoid the breaking change. @justinmc @xster ready for review

// This also relies on the animation to update its status at the end of the
// gesture. See the _CupertinoBackGestureController.dragEnd for how
// cupertino page route achieves that.
if (manifest.fromRoute?.navigator?.userGestureInProgress == true)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing that troubles me in this approach is that we push the responsibility, that gesture should trigger animation update when it ends, to the route transition class. I am worrying the third party library developer might trip on this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we already crossed that bridge. Since Navigator and Hero are both from the widgets package and heroes.dart is already making use of the user gesture state.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still work if the user dragged it to the end and dropped it exactly there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we have tests to ensure that

testWidgets('test edge swipe then drop back at ending point works', (WidgetTester tester) async {

testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async {

@chunhtai
Copy link
Contributor Author

chunhtai commented Jun 5, 2020

@justinmc the pr has changed a lot since your last review, can you take another look?

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just two nits.

@@ -533,6 +533,14 @@ class _HeroFlight {
}

void _handleAnimationUpdate(AnimationStatus status) {
// The animation will not finish until the user lift their finger, so we
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The animation will not finish until the user lift their finger, so we
// The animation will not finish until the user lifts their finger, so we

box = tester.renderObject(find.byKey(container)) as RenderBox;
final double firstPosition = box.localToGlobal(Offset.zero).dx;
// Checks the hero is in-transit.
expect(finalPosition > firstPosition, isTrue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Same thing, but maybe the error message is more informative if you do this:

Suggested change
expect(finalPosition > firstPosition, isTrue);
expect(finalPosition, greaterThan(firstPosition));

@chunhtai chunhtai removed the c: API break Backwards-incompatible API changes label Jun 5, 2020
@chunhtai chunhtai merged commit 5eaaad4 into flutter:master Jun 5, 2020
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
flutter#58024)

* fix cupertino page route dismisses hero transition when swipe to the edge

* add more comment

* addressing comments
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 31, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CupertinoNavigationBar dissapears when sliding back
5 participants