4

Animations in Navigation Compose

 2 years ago
source link: https://medium.com/androiddevelopers/animations-in-navigation-compose-36d48870776b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Animations in Navigation Compose

Jetpack Compose moves the bar on animations from ‘polish, if we have the time’ to ‘so easy there’s no reason to not do it’ and a big part of that are screen level transitions. That’s why Navigation Compose has been working towards a set of solutions that solve three specific cases:

  • Using only the stable Animation APIs in Compose 1.0.0
  • Enabling support for Experimental Animation APIs present in Compose 1.0.0
  • Building towards the future Animation APIs (shared element transitions!!!) in Compose 1.1.0 and beyond

Each of these requires a slightly different approach, which we’ll cover here.

Compose 💚 Animations

Jetpack Compose has come a long, long way since the first 0.1.0-dev01 release through to the new Compose 1.0.1 release. One of the areas that has been a huge improvement over the View world has been that of animations and transitions. In the quest for the perfect animation APIs, a lot of changes were made as Compose marched towards 1.0.0.

While a number of lower level Animation APIs like the incredibly powerful animateTo() and animate*AsState() are stable, foundational parts of Compose at this point, there’s a whole class of APIs on top of those building blocks marked with @ExperimentalAnimationApi.

Experimental APIs and Semantic Versioning

An Experimental API (any API using @RequiresOptIn API in Kotlin land) means that these APIs are subject to change at any point. This means that those APIs might be changed, improved, or replaced in any future release — maybe it is Compose 1.1.0-alpha04 or 1.2.0-alpha08. As such, any library that is built on those Experimental APIs would immediately crash and fail if you were to update the version of Compose you were using and not also update that library at the same time. (If you were along for the ride for early Compose releases, you know this pain.)

All AndroidX libraries, Navigation and Compose included, follow strict semantic versioning as explained on the AndroidX releases page. This means that any API that isn’t experimental is set in stone once a library goes to its Release Candidate (RC) phase. It would take a major version bump (i.e., a ‘2.0’) to make breaking API changes to these stable APIs.

This is great when it comes to forward and backward compatibility — for instance, you can upgrade your Fragment version to try out a new alpha while keeping your other dependencies on their stable releases and everything just works.

However, it also means that experimental APIs, being APIs that can shift out from underneath you, are strictly forbidden across different artifact groups — again, upgrading your version of androidx.fragment shouldn’t break androidx.appcompat. This also applies to androidx.navigation and androidx.compose.animation.

Getting Navigation 2.4 to stable

Navigation 2.4 is a big release as both the first release of Navigation Compose as well as the first release with multiple back stack support for both Navigation Compose and Navigation with Fragments. This means we’re wrapping up the remaining related API requests in preparation for moving through beta, RC, and to stable.

For Navigation Compose, this means that we’re building on top of Compose 1.0.1 with the goal of being forward compatible for those of you who want to (or have already!) moved to start depending on Compose 1.1.0-alpha01 and beyond.

That forward compatibility requirement means that any code in Navigation Compose 2.4.0 can only rely on stable Compose Animation APIs. This is how we were able to add crossfade support in Navigation 2.4.0-alpha05 — in the world of Compose, jump cuts should be the first thing on your list to banish completely.

This limitation on only using stable Compose Animation APIs means that APIs such as AnimatedContent aren’t something Navigation 2.4 can use directly to offer the kind of rich animation control you’d want directly as part of Navigation 2.4. However, the extensible nature of Navigation means that the underlying framework is already built and available.

Introducing: Accompanist Navigation Animation!

That underlying support for animating between destinations is why we’re able to release Accompanist Navigation Animation, built off of today’s release of Navigation 2.4.0-alpha06. The Navigation Animation artifact provides its own set of animation enabled versions of the Navigation Compose APIs you’ve been using:

  • Replace rememberNavController() with rememberAnimatedNavController()
  • Replace NavHost with AnimatedNavHost
  • Replace import androidx.navigation.compose.navigation with import com.google.accompanist.navigation.animation.navigation
  • Replace import androidx.navigation.compose.composable with import com.google.accompanist.navigation.animation.composable

At first glance, the appearance of your app hasn’t changed: the default animations are still the same type of fadeIn and fadeOut that the crossfade found in Navigation 2.4 does for you. However, you’ll gain one crucial new feature: the ability to configure those animations and substitute in your own transitions between screens.

This control comes in the form of four new parameters found on every composable destination:

  • enterTransition: specifies the animation that runs when you navigate() to this destination.
  • exitTransition: specifies the animation that runs when you leave this destination by navigating to another destination.
  • popEnterTransition: specifies the animation that runs when this destination re-enters the screen after going through a popBackStack(). This defaults to the enterTransition.
  • popExitTransition: specifies the animation that runs when this destination leaves the screen after you pop it off the back stack. This defaults to the exitTransition.

In each case, these parameters have the same format:

enterTransition: (
(
initial: NavBackStackEntry,
target: NavBackStackEntry
) -> EnterTransition?
)? = null,

Each takes a lambda. That lambda is given the NavBackStackEntry of where you are coming from (the initial) and where you are going to (the target). For example, for the enterTransition, the entering destination is the target — the one you are applying the enterTransition to. The opposite applies to the exitTransition: the initial screen is the one you are applying the exit transition to.

This allows you to write your destination such as:

Or, control your animation based on where you’re coming from / going to:

Here, the friends list screen controls its exit transition to the profile screen and the profile screen controls its enter transition from the friends list, allowing for a custom slide over animation between these two destinations. We also see the usage of null to mean “use the defaults”. Those defaults come from the parent navigation graph and then the parent’s parent’s navigation graph, all the way up the hierarchy to the root AnimatedNavHost. This means that setting default animations (say, the timing on crossfades) is possible just by changing the global enterTransition and exitTransition on your AnimatedNavHost.

If you instead want to change the default for only one subgraph (say, your login flow always uses a horizontal slide in animation), you can set that animation on the nested graph level as well:

Note how we use the hierarchy extension method to determine if the destination is actually part of the login graph — that way our transition to the login graph and from the login graph just use the default transition (or whatever transition you’ve set at the higher level).

Whenever you have a directional transition such as sliding in horizontally, this is where the difference between enterTransition and popEnterTransition becomes incredibly handy — you’ll be able to avoid cases where one screen is sliding to the right while the other slides to the left.

Accompanist serves as the booster rockets for Jetpack libraries and let us deliver experimental features right now as the work on Compose 1.1 progresses.

Add Accompanist Navigation Animation via:

implementation
"com.google.accompanist:accompanist-navigation-animation:0.16.1"

The future of Navigation Compose and Animations

With Navigation 2.4 based on Compose 1.0.1 and Accompanist Navigation Animation stretching the limits of Compose 1.0 via experimental APIs, there’s something else on the horizon: Compose 1.1. Looking at the Compose Roadmap, there’s one really important upcoming feature to get excited about:

Support shared element transitions

Our goal for Navigation 2.5 is to bring all the goodness of Compose 1.1 to Navigation Compose. That means as animation APIs lose their experimental status, we can fold them directly into Navigation Compose. It also means that we can build the API that we know will support shared element transitions as they become available.

It also means that Accompanist Navigation Animation should be considered as a temporary measure: once Navigation Compose itself offers the same level of animation APIs (tailored based on your feedback!), you’ll be able to depend on it directly and remove Accompanist Navigation Animation entirely.

Go forth and animate

Balancing stability and the forward and backward compatibility requirements we put on ourselves as a Jetpack library with the ability to ship features quickly means this isn’t as straightforward as we’d like. Accompanist has been a huge boon as Jetpack Compose gains momentum and accelerates beyond the need for those booster rockets. I’d like to thank

and all the developers who put time into Accompanist, the entire team behind Compose, and all of you for helping shape the future of Android development.

PS: if you’re looking for even more Navigation+Accompanist goodies, check out the also brand new Accompanist Navigation Material!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK