Repository navigation
Predictive Back Gesture animation doesn't and can't implement material design spec to match native behavior #153577
Copy link
Copy link
Open
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listf: routesNavigator, Router, and related APIs.Navigator, Router, and related APIs.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.platform-androidAndroid applications specificallyAndroid applications specificallyteam-frameworkOwned by Framework teamOwned by Framework teamtriaged-frameworkTriaged by Framework teamTriaged by Framework team
Description
Steps to reproduce
Use PredictiveBackPageTransitionsBuilder()
Expected results
The same animations and behavior as the native apps and system.
Spec: https://developer.android.com/design/ui/mobile/guides/patterns/predictive-back
Actual results
In the "pre-commit" part of the animation:
- the front page abruptly disappears when swiping across 35% of the screen
- the front and back pages ignore if the gesture started from the left or right edge
- the front and back pages don't go up and down following finger
In the "post-commit" part of the animation:
- the animation goes way too fast (<100ms, should be ~300ms)
- the animation blocks all user inputs for about 700ms after the animation is visually finished
- the animation is the same as the "pre-commit" one, which is not what happens in the rest of Android and in the spec.
1. and 6. can be worked around by writing a custom PageTransitionBuilder.
2. and 3. can be partially worked around: only for the front page.
4. and 5. cannot be worked around without editing the SDK source code itself.
Flutter Doctor output
Doctor output
flutter doctor -v devenv-shell-env
[✓] Flutter (Channel master, 3.24.0-1.0.pre.605, on NixOS 24.05 (Uakari) 6.8.12, locale en_US.UTF-8)
• Flutter version 3.24.0-1.0.pre.605 on channel master at /home/paulg/Repos/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision bced008679 (14 hours ago), 2024-08-15 22:29:24 -0400
• Engine revision a8fefc8118
• Dart version 3.4.3
• DevTools version 2.38.0
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at /nix/store/nzwnj7rq8a6cvzbsszf4n9zfvx101zm5-androidsdk/libexec/android-sdk
• Platform android-34, build-tools 30.0.3
• ANDROID_HOME = /nix/store/nzwnj7rq8a6cvzbsszf4n9zfvx101zm5-androidsdk/libexec/android-sdk
• ANDROID_SDK_ROOT = /nix/store/nzwnj7rq8a6cvzbsszf4n9zfvx101zm5-androidsdk/libexec/android-sdk
• Java binary at: /nix/store/l7pwy1rxdrb13svqandm720d06fycd8c-openjdk-17.0.11+9/lib/openjdk/bin/java
• Java version OpenJDK Runtime Environment (build 17.0.11+9-nixos)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• CHROME_EXECUTABLE = /nix/store/cg5bvzxml5bbdw8wlrywb6q7hpdjq0ij-google-chrome-127.0.6533.88/bin/google-chrome-stable
[✓] Linux toolchain - develop for Linux desktop
• clang version 16.0.6
• cmake version 3.29.6
• ninja version 1.12.1
• pkg-config version 0.29.2
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).
[✓] Connected device (3 available)
• Pixel 7 Pro (mobile) • 192.168.1.13:43591 • android-arm64 • Android 15 (API 35)
• Linux (desktop) • linux • linux-x64 • NixOS 24.05 (Uakari) 6.8.12
• Chrome (web) • chrome • web-javascript • Google Chrome 127.0.6533.88
[✓] Network resources
• All expected network resources are available.
! Doctor found issues in 1 category.Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listf: routesNavigator, Router, and related APIs.Navigator, Router, and related APIs.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.platform-androidAndroid applications specificallyAndroid applications specificallyteam-frameworkOwned by Framework teamOwned by Framework teamtriaged-frameworkTriaged by Framework teamTriaged by Framework team
Activity
PaulGrandperrin commentedon Aug 16, 2024
I wrote a few more detailed comments on this PR while investigating: #141373
[-]Predictive Back Gesture animation can't implement material design spec [/-][+]Predictive Back Gesture animation doesn't and can't implement material design spec [/+][-]Predictive Back Gesture animation doesn't and can't implement material design spec [/-][+]Predictive Back Gesture animation doesn't and can't implement material design spec to match native behavior[/+]PaulGrandperrin commentedon Aug 17, 2024
I guess it's important to note that I'm using Android 15 (API 35), when the current SDK implementation is based on Android 14 (API 34): https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart#L181
I don't remember how this animation looked on this version, so maybe flutter's implementation was more faithful than what I'm describing here.
huycozy commentedon Aug 19, 2024
Hi @PaulGrandperrin
I checked this on Flutter and Android native apps and I can see different swipe gesture distances. In Flutter app, I need to swipe longer than on Android native.
Demo
Screen.Recording.2024-08-19.at.15.12.53.mov
Screen.Recording.2024-08-19.at.15.24.56.mov
Can you please be more specific on these points?
PaulGrandperrin commentedon Aug 19, 2024
To be more specific, when
BackEvent.progressbecomes bigger than 0.35,animation.valuebecomes smaller than 0.65, and when this happensfadeTweenwill select the firstTweenSequenceItemwhich goes from0.0to0.0. Since this controls the opacity, the front page abruptly disappear at progress = 35%. Here's the code:I have no idea was it was supposed to originally, but there's clearly at least a typo in the range values.
PaulGrandperrin commentedon Aug 19, 2024
I think a lot can be explained by the differences between Android 14 and 15. The current code was tested against 14, and I now realize that on this version, the animation mostly works for several reasons:
However, I strongly suppose the 700ms of unresponsive app after a route pop is still there.
I captured on my Android 15 phone, what the current code looks like: https://drive.google.com/file/d/1ZfraE_JL6PA27aD0gMij3kpzcvOnOEcY/view?usp=sharing
You can see that
Here's how it looks on this PR: https://drive.google.com/file/d/1ZiOU_fUCc6v_npc2rTg405iyWSSXdDHj/view?usp=sharing
I also show what the animation looks like natively in the Settings.
PaulGrandperrin commentedon Aug 19, 2024
One important thing is that on Android 15, which will be released soon, the predictive back gestures are enabled by default.
So a lot of people will soon be exposed to it, and the flutter app devs won't be able to fix those issues, even with a custom transition, because part of the responsible code is in
TransitionRoute, like the curve controlling the postCommit animation pace.PaulGrandperrin commentedon Aug 19, 2024
To better see how the animation adapts from which side it was started: https://drive.google.com/file/d/1ZiqAj-TErJsZuU5Bg2i8gLfgvjBV0Kvp/view?usp=sharing
PaulGrandperrin commentedon Aug 19, 2024
Oh and I'm thinking about another reason why it didn't shock anyone until now, on the Android emulator the frame rate is already often choppy and targets I guess 60fps.
On a real 120fps phone, when building in release mode, the issues I mentioned are a lot more striking.
huycozy commentedon Aug 20, 2024
Thanks for providing more information. I don't have an Android 15 device now, I will label this for other's input.
8 remaining items
justinmc commentedon Aug 26, 2024
On the topic of Shared Element vs. Full Screen Surfaces, it looks like Android has now defaulted to Shared Element. This is what I see if I create a plain Compose app on API 35:
Video of native API 35 default transition between Activities
Screencast.from.2024-08-26.12-44-42.webm
Also, I don't see the Full Screen Surfaces animation anywhere if I look for it in the system Android 15 apps.
So I think that Flutter should default to Shared Element transition and not worry about Full Screen Surfaces. Apologies for previously saying the opposite. It looks like the default transition on Android has changed from then and now.
That PR is a little stale at this point, but my intention was to make the existing OpenContainer transitions work with predictive back. My implementation probably was intended to look like the Shared Element transition mentioned above, but where the popped page animates to look like it's coming from some widget on the previous page.
So @maRci002 since you still have your old code, are you interested in opening a PR to update the PredictiveBackPageTransition animation to look like Shared Element? It seems like #153635 is not intending to land.
maRci002 commentedon Aug 26, 2024
My observation is that Android native (using Intents) applies the
Shared Elementtransition; however, when Compose itself animates, it applies theFull Screen Surfacesanimation. The official predictive back codelab uses theFull Screen Surfacesanimation.I have created a Compose application where both can be tried out:
MainActivity.kt— don't forget to toggle theuseNativeAnimationsvariable to try out both:MainActivity.kt
AndroidManifest.xml: Don't forget to addandroid:enableOnBackInvokedCallback="true"and also register the second activity like this:<activity android:name=".SecondActivity" />In
gradle/libs.versions.toml, increase thenavigationComposeto2.8.0-beta02(this is the minimum version required to support the predictive back feature) or higher, such as2.8.0-alpha08.Compose - androidx.navigation:navigation-compose:2.8.0-alpha08
compose_predictive_back.mp4
Native (using Intents)
native_predictive_back.mp4
Yes, I am interested in opening a PR. The
PredictiveBackPageTransitionsBuildercould be made more generic, for instance, by having its own transition builder. The default could bePredictiveBackPageTransitionsBuilder.sharedElementTransitionBuilder, but the old one,PredictiveBackPageTransitionsBuilder.fullScreenSurfacesTransitionBuilder, would still be available.justinmc commentedon Sep 5, 2024
@maRci002 Ah good catch, I guess ideally we should have both. Your approach looks good. I'm happy to help review if you open a PR.
NikosTsesmelis commentedon Jan 20, 2025
I would like to add that the corners on the native transition are rounded in my device but in the flutter implementation they are not
justinmc commentedon Apr 9, 2025
This will be partially fixed by #154718. The transition of the incoming route (delegatedTransition) will happen in a separate PR.
For future reference he delegatedTransition seems to have three components:
Edit Some of this animation happens before commit, and currently, delegatedTransform doesn't run until after the commit. There will probably be some kind of infrastructure needed to support that. I assume just using _PredictiveBackGestureDetector in the delegatedTransition won't be enough.
Shared element transition for predictive back (#154718)
flutter-triage-bot commentedon Aug 13, 2025
This issue is assigned to @justinmc but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!