- Animations in Navigation Compose
- Compose 💚 Animations
- Experimental APIs and Semantic Versioning
- Getting Navigation 2.4 to stable
- Introducing: Accompanist Navigation Animation!
- The future of Navigation Compose and Animations
- Go forth and animate
- Урок 26. Navigation. Параметры навигации
- destination Fragment
- Attributes
- Arguments
- Actions
- Deep links
- destination Activity
- Attributes
- Arguments
- Deep links
- Action
- Атрибуты
- Transitions
- Argument Default Values
- Pop Behaviour
- Launch Options
- NavOptions
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:
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.
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 Chris Banes 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!
Источник
Урок 26. Navigation. Параметры навигации
В этом уроке разбираемся, как задавать параметры при навигации.
Полный список уроков курса:
В графе у нас есть три основных объекта, у которых мы можем задавать параметры: это destination Fragment, destination Activity и action.
Рассмотрим каждый из них подробно.
destination Fragment
Attributes
Type — это тип destination, в данном случае Fragment.
Label — текстовое описание. Его можно получить в коде.
Также оно будет использовано в случае интеграции с Navigation Drawer. Об этом будет следующий урок.
В качестве значения вы можете указать строковый ресурс, например: @string/fragment3_label
ID — уже знакомый нам атрибут, используется в методе navigate для навигации к этому destination. ID генерируется автоматически, но всегда можно ввести свое более осмысленное значение.
Class — класс фрагмента.
Set Start Destination — этой кнопкой можно destination сделать стартовым. Он будет отображаться первым при запуске.
Arguments
Возможность задать аргументы с значениями по умолчанию. Это мы подробно рассмотрели в прошлом уроке.
Actions
Список action, выходящих из этого destination. На скриншоте выше только один action, который ведет в SecondActivity. Но их может быть несколько.
Deep links
Об этом поговорим в отдельном уроке.
destination Activity
Attributes
Type, Label, ID, Class — аналогичны атрибутам destination Fragment.
Action и Data — соответствуют стандартным полям action и data в Intent классе. Заполняете их здесь и в Activity достаете из getIntent().getAction() и getIntent().getData().
Pattern — это примерно то же, что и Data, но с параметрами. Т.е. вы здесь задаете свой Uri и в нем указываете имена параметров в фигурных скобках.
На скриншоте выше я указал Uri: content://media/photo/
У него два параметра folder и id. От нас потребуется при вызове Activity передать значения для этих параметров через Bundle.
Параметры должны быть строковые.
В результате в Activity метод getIntent().getData() вернет нам: content://media/photo/camera/100.jpg
Arguments
Аналогичны аргументам destination Fragment.
Deep links
Об этом поговорим в отдельном уроке.
Обратите внимание, что нет списка Actions. Потому что граф действует только в пределах своего Activity. Переход в другое Activity — это уход из этого графа и дальнейшие перемещения будут определяться уже другим графом.
И нет кнопки Set Start Destination. Выходная из графа точка не может быть стартовой.
Action
Напомню, что action — это возможность указать дополнительные параметры при вызове destination. Рассмотрим эти параметры.
Пример: action из Fragment2 в Fragment3
Атрибуты
C Type и ID все понятно.
Destination — показывает, куда ведет action. Т.е. какой destination будет открыт, если вызвать метод NavController.navigate с ID этого action.
Transitions
Возможность задать анимацию перехода между destination.
Этот action ведет с Fragment2 на Fragment3. Соответственно:
Enter — анимация для появления Fragment3
Exit — анимация для исчезания Fragment2.
А когда возвращаемся с Fragment3 на Fragment2, то
Pop Enter — анимация появления Fragment2
Pop Exit — анимация исчезанияFragment3
Под капотом эти анимации просто передаются в FragmentTransaction:
Argument Default Values
Аргументы берутся из destination, в который ведет action. Здесь можно задать им значения по умолчанию.
Pop Behaviour
Допустим у нас есть три destination.
Мы поочередно их открываем в Activity: fragment1 > fragment2 > fragment3.
По каким то причинам нам надо, чтобы при возврате назад из fragment3 мы сразу попадали в fragment1 (минуя fragment2). Для этого мы создаем action, который ведет из fragment2 в fragment3 и укажем ему Pop To = fragment1. Теперь при вызове этого action система сбросит backStack до указанного в Pop To фрагмента.
В результате при возврате из Fragment3 попадаем в Fragment1.
Если включен чекбокс Inclusive, то destination, указанный в Pop To также будет закрыт и мы попадем на destination, который был перед ним.
Launch Options
Эти параметры зависят от того, куда ведет action: в Activity или в фрагмент.
Рассмотрим сначала для случая, когда action ведет в Activity.
Single Top — добавляет в Intent вызова Activity флаг Intent.FLAG_ACTIVITY_SINGLE_TOP
Document — добавляет в Intent вызова Activity флаг Intent.FLAG_ACTIVITY_NEW_DOCUMENT
Clear Task — cбрасывает стэк текущего графа до стартового destination. Добавляет в Intent вызова Activity флаг Intent.FLAG_ACTIVITY_CLEAR_TASK. Не очень понятный режим. Возможно еще просто не доведен до ума.
Если же action ведет в фрагмент:
Single Top — если текущий фрагмент тот же, что и вызываемый, то вызов будет проигнорирован.
Document — похоже, что никак не используется.
Clear Task — стэк текущего графа очищается до стартового фрагмента. Транзакция перехода в новый фрагмент не добавляется в backStack. Соответственно, вызываемый фрагмент заменяет текущий и становится единственным.
NavOptions
Все выше рассмотренные параметры можно задавать программно в объекте NavOptions и далее передавать этот объект в метод navigate.
Источник