Skip to content
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

Cupertino navigation bars transitionBetweenRoutes fidelity update #164956

Merged
merged 22 commits into from
Mar 20, 2025

Conversation

victorsanni
Copy link
Contributor

@victorsanni victorsanni commented Mar 11, 2025

In the before Flutter video, drag happens after the 17 second mark.

Flutter before

Flutter.before.mov

Flutter after

Flutter.after.4.mov

Flutter back swipe drag gesture

flutter.after.drag.2.mov

Native iOS

native.mov

Flutter scaled back chevron and large title after

flutter.scaled.and.label.mov

Native iOS scaled back chevron and large title

native.scaled.back.chevron.mov

Native iOS is probably using a spring simulation. This is the closest curve we have to the native transition, but should be updated in the future with the exact values.

Fixes Cupertino navigation bars transitionBetweenRoutes fidelity update

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: cupertino flutter/packages/flutter/cupertino repository labels Mar 11, 2025
@victorsanni victorsanni marked this pull request as ready for review March 11, 2025 18:50
Copy link
Contributor

@MitchellGoodwin MitchellGoodwin left a comment

Choose a reason for hiding this comment

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

Looks MUCH better.

);

Widget child = bottomNavBarBottom.child;
final Curve animationCurve =
animation.status == AnimationStatus.forward
? Curves.easeOutQuart
Copy link
Contributor

Choose a reason for hiding this comment

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

The forward case looks a little fast. Ideally, the navbar contents would not go ahead of the content behind it, I think it's a little distracting. The reverse case looks good, in my opinion.

It looks like the Hero widget applies it's own curve as well. Is that interfering at all?

How does this look when dragging the whole time? As long as the drag gesture is still active, the base curve of the transition is linear.

Choose a reason for hiding this comment

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

The forward case looks a little fast. Ideally, the navbar contents would not go ahead of the content behind it, I think it's a little distracting. The reverse case looks good, in my opinion.

yeah it feels too fast and the fact that it goes ahead of the content makes it look bad visually, especially when manually dragging to pop a page.

I also found a bug when swiping between pages, if I start swiping from the furthest point the large title doesn't start animating immediately creating an unpleasing visual bug, but if I start swiping to pop from a point far from the edge it animates as expected, here's a screen recording of this behaviour:

screen recording

Copy link
Contributor

Choose a reason for hiding this comment

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

I also found a bug when swiping between pages, if I start swiping from the furthest point the large title doesn't start animating immediately creating an unpleasing visual bug, but if I start swiping to pop from a point far from the edge it animates as expected, here's a screen recording of this behaviour

That's likely because the page transition is on a linear curve during the drag, while the navbar is still on a flipped easeOutQuart curve.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible for the header to simply follow the content's x coordinate? If we can't get the exact curve then simply doing this should be acceptable.

Choose a reason for hiding this comment

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

Is it possible for the header to simply follow the content's x coordinate? If we can't get the exact curve then simply doing this should be acceptable.

I also thought of this, it sounds like a reasonable thing to do if the curve requires lots of work to look somewhat right, also since this is a temporary change and will be tweaked again as mentioned in the issue description to use a spring simulation.

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 tried all the curves we have, none of them could follow the content. There's something funky happening behind the scenes that I can't put a finger on. @MitchellGoodwin mentioned that the Hero might be applying its own curve, maybe that's why.

Either way I used custom curves to approximate the native animation.

Copy link

@MaherSafadii MaherSafadii left a comment

Choose a reason for hiding this comment

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

it look more polished now, looks good for when there's only a large title, but with the search field not so much, can you make the search field that's on the page that's getting another page pushed on to (the previous page), slide with the same curve as the pages content because currently there a lot of overlapping happening with them especially when manually dragging, things are feeling better overall, the pushed title felt flimsy before this pr now it feels snappy which is good.

);

Widget child = bottomNavBarBottom.child;
final Curve animationCurve =

Choose a reason for hiding this comment

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

the title being ahead of the page looks jarring, maybe a custom animation curve could be used instead of the current built-in ones if they can't match current needs, because it seems like it needs a very specific curve, based on my observation of the native side, maybe you can use the base of the curve that the page content animates in, but tweak it a bit, make it slightly slower at the beginning and faster at the end but not to fast to the point where it doesn't overflow out of the page's content.

);

Widget child = bottomNavBarBottom.child;
final Curve animationCurve =
animation.status == AnimationStatus.forward
? Curves.easeOutQuart

Choose a reason for hiding this comment

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

Is it possible for the header to simply follow the content's x coordinate? If we can't get the exact curve then simply doing this should be acceptable.

I also thought of this, it sounds like a reasonable thing to do if the curve requires lots of work to look somewhat right, also since this is a temporary change and will be tweaked again as mentioned in the issue description to use a spring simulation.

Copy link

@MaherSafadii MaherSafadii left a comment

Choose a reason for hiding this comment

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

looks awesome now, the curves are snappy like native and aren't overlapping aggressively like before, the bug where if you start swiping to pop from the devices border is still present, the title doesn't start animating until you swipe a longer distance, also the the large title when animating to the previous page title in the back button needs updating now seems it needs to match the speed the large title that's entering and leaving, other than that, everything looks and works fine.

Copy link
Contributor

@MitchellGoodwin MitchellGoodwin left a comment

Choose a reason for hiding this comment

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

I have one concern on the type checking but other than that, LGTM. I think this looks so much better now. It would probably be better to readdress the spring simulations first before polishing this further.

// The bottom widget animates linearly during a backswipe by a user gesture.
userGestureInProgress
// The parent of the hero animation, which is the route animation.
? (animation as CurvedAnimation).parent
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should check to see if it is a CurvedAnimation. That way if it changes in the Hero implementation in the future, this doesn't break.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we check or assert?

Copy link
Contributor

Choose a reason for hiding this comment

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

Good question. I think assert would be better, so this code doesn't just hang around if that happens.

// The large title animates linearly during a backswipe by a user gesture.
userGestureInProgress
// The parent of the hero animation, which is the route animation.
? (animation as CurvedAnimation).parent
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

@MaherSafadii
Copy link

just checked the latest changes and it looks good, I also agree with Mitchels comment:

It would probably be better to readdress the spring simulations first before polishing this further.

things look good so far, it isn't worth putting more effort to match the native side down to the smallest detail if it's going to be revisited and get implemented with a spring simulation sometime later.

@MaherSafadii
Copy link

can you make it that the chevron finishes animating as soon as the page push animation finishes because currently it starts animating when the push animation finishes unlike native.

Copy link
Contributor

@dkwingsmt dkwingsmt left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

@victorsanni
Copy link
Contributor Author

can you make it that the chevron finishes animating as soon as the page push animation finishes because currently it starts animating when the push animation finishes unlike native.

Hi @MaherSafadii can you confirm if this has been fixed?

@MaherSafadii
Copy link

can you make it that the chevron finishes animating as soon as the page push animation finishes because currently it starts animating when the push animation finishes unlike native.

Hi @MaherSafadii can you confirm if this has been fixed?

it works properly now, the only noticeable thing left is the large title animating to the previous button is a bit slow, should it be fixes in this PR or is it for another one?

@victorsanni
Copy link
Contributor Author

it works properly now, the only noticeable thing left is the large title animating to the previous button is a bit slow, should it be fixes in this PR or is it for another one?

I see that as well, taking a look.

@victorsanni
Copy link
Contributor Author

it works properly now, the only noticeable thing left is the large title animating to the previous button is a bit slow, should it be fixes in this PR or is it for another one?

This should be fixed now.

Copy link

@MaherSafadii MaherSafadii left a comment

Choose a reason for hiding this comment

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

It's way better now, it feels snappy, but there seems to be some aggressive font weight and text position changing that makes it look jarring especially in normal speed, here are some screen recordings that show it clearly:

Slow motion:
https://github.com/user-attachments/assets/9ccecad0-9a8b-4680-b7c7-2f4b6166850b

Normal speed:
https://github.com/user-attachments/assets/e645070b-01c2-4a36-aeb4-810f0175c935

another thing I just remembered is that on native when you push to a page, the default behaviour for the previous button title is it to be the large title that's set in the previous page, but in flutter by default its an empty string with just a chevron, it feels like a chore every time to make it match the correct behaviour by adding a line of code every time, making it behave like native would create a better experience and also for localization it would help since it takes the string from the large text from the previous page, so if its localized it will automatically be localized in the previous button.

@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 19, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Mar 19, 2025
@victorsanni victorsanni removed this pull request from the merge queue due to a manual request Mar 19, 2025
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 19, 2025
@victorsanni
Copy link
Contributor Author

there seems to be some aggressive font weight and text position changing that makes it look jarring especially in normal speed

Not 100% sure but I think this is an impeller text rendering issue.

@victorsanni
Copy link
Contributor Author

I think native iOS nav bars keep the background color per page

native.iOS.background.mov

so instead of removing the background completely, we should just have both nav bars keep their individual backgrounds (vs. previously where they shared the same background)

nav.bar.readd.background.mov

This also prevents an issue where transitions from a page that has been scrolled shows the scrollview's content underneath the nav bar mid transition.

@MitchellGoodwin
Copy link
Contributor

Not 100% sure but I think this is an impeller text rendering issue.

I think this is because it switches from 'CupertinoSystemDisplay' and 'CupertinoSystemText', which each have different letter spacing and font weight handling. That might be a bit of a rabbit hole, so I'd recommend leaving that for a separate issue and PR.

Copy link
Contributor

@MitchellGoodwin MitchellGoodwin left a comment

Choose a reason for hiding this comment

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

Background changes LGTM! 👍

@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 20, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Mar 20, 2025
Merged via the queue into flutter:master with commit 1fa9254 Mar 20, 2025
75 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cupertino navigation bars transitionBetweenRoutes fidelity update
4 participants