AndroidCompose Navigation导航精通2-过渡动画与路由切换

资源获取方式

关注公众号ZhillerDev,后台发送 android001 就可以获取项目源码及资料啦~
感谢您关注wx公众号,个人将快马加鞭为大家提供更优质的文章与资源!
点击前往微信观看本文章

前言

文章总索引:点击前往

在当今的移动应用开发中,导航是用户与应用交互的核心环节。随着 Android Compose 的兴起,它为开发者提供了一种全新的、声明式的方式来构建用户界面,同时也带来了更简洁、更高效的导航实现方式。本系列教程将深入探讨如何在 Android Compose 中实现各种导航功能,从基础的页面跳转到复杂的导航架构设计,帮助你全面掌握 Compose Navigation 的精髓。

在本系列的第二部分,此时将会学习三种不同的路由切换过渡动画,并了解如何正确高效的封装composable方法,实现路由的快速注册。


路由切换

NavController

NavController用于控制APP全局的路由导航,他也存在一种变体,下面是两个主要的controller对象

  1. NavController:Navigation导航的核心类,负责管理导航图(NavGraph)和返回栈(Back Stack),并提供导航操作的方法
  2. NavHostController:是 NavController 的一个子类,专门用于 Compose 环境。它继承了 NavController 的所有功能,并提供了一些额外的 Compose 特定的功能

除上述所述之外,您最好可以在使用过程中利用下方三个特点:

  1. 一般页面内基本都使用NavController对象
  2. 只有我们在定义NavHost时才会用到NavHostController对象
  3. 务必保证全局有且只有一个NavController对象,也就是说他必须是单例的(所以我们一般都会从MainActivity就直接创建NavController,然后层层传递下去,就可以保证不会创建重复的对象)

如下代码即在定义NavHost时使用了NavHostController对象:

@Composable
fun NavGraphs(
  modifier: Modifier = Modifier,
  navController: NavHostController = rememberNavController(),
  startDestination: String = NavRoutes.INIT_NAV_ROUTE
) {
  NavHost(modifier = modifier, navController = navController, startDestination = startDestination) {
    ...
  }
}

BackStackEntry

路由返回栈(BackStackEntry)拥有以下几个特点:

  1. 后进先出(LIFO):
    返回栈采用后进先出的数据结构,即最后被访问的页面位于栈顶,最先被访问的页面位于栈底。
    当用户从一个页面导航到另一个页面时,新的页面会被推入栈顶。
    当用户点击返回按钮时,栈顶的页面会被弹出,用户返回到前一个页面。
  2. 初始目的地:
    当用户打开应用时,NavController 会将第一个目的地推送到返回栈的顶部。
  3. 导航操作:
    每次调用 NavController.navigate() 时,目标页面会被推入返回栈的顶部。
    调用 NavController.popBackStack() 时,会将当前页面从返回栈中弹出,并导航到前一个页面。
  4. 返回到特定目的地:
    你可以使用 popBackStack() 方法导航到特定的目的地,并可以选择是否将该目的地从返回栈中弹出。
    例如,navController.popBackStack(R.id.destinationId, true) 会导航到指定的目的地,并将其从返回栈中弹出。

你可以先拿到一个NavController对象,再根据它来得到当前的路由返回栈;
获取方式如下所示:

val navController = rememberNavController()
val currentBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = currentBackStackEntry?.destination

过渡动画

过渡原理

修改导航过渡动画主要依赖于 AnimatedNavHost 和 composable 函数中的 enterTransition、exitTransition、popEnterTransition 和 popExitTransition 参数。这些参数允许你自定义页面跳转时的动画效果;

每一个composable都有下面四个动画参数,通过给予不同的动画方法、提供适合的过渡延时,即可得到美观的路由切换过渡效果

  1. enterTransition:定义页面进入时的动画。
  2. exitTransition:定义页面退出时的动画。
  3. popEnterTransition:定义从栈中弹出页面时的进入动画。
  4. popExitTransition:定义从栈中弹出页面时的退出动画。

缩放动画

动画效果:

  1. 切换到新路由时:旧页面缩小后逐渐消失,新页面从小到大缩放后逐渐显现
  2. 回退到上一路由时:上述动画反过来
fun NavGraphBuilder.composableScale(
  route: String,
  arguments: List<NamedNavArgument> = emptyList(),
  deepLinks: List<NavDeepLink> = emptyList(),
  content: @Composable (NavBackStackEntry) -> Unit
) {
  composable(route = route, arguments = arguments, deepLinks = deepLinks, enterTransition = {
    // 新页面:由内往外扩展 + 渐变显示
    fadeIn(animationSpec = tween(300)) + scaleIn(initialScale = 0.8f, animationSpec = tween(300))
  }, exitTransition = {
    // 旧页面:向内缩放 + 渐变消失
    fadeOut(animationSpec = tween(300)) + scaleOut(targetScale = 0.8f, animationSpec = tween(300))
  }, popEnterTransition = {
    // 返回时:新页面(实际上是旧页面)由内往外扩展 + 渐变显示
    fadeIn(animationSpec = tween(300)) + scaleIn(initialScale = 0.8f, animationSpec = tween(300))
  }, popExitTransition = {
    // 返回时:旧页面(实际上是新页面)向内缩放 + 渐变消失
    fadeOut(animationSpec = tween(300)) + scaleOut(targetScale = 0.8f, animationSpec = tween(300))
  }) { entry ->
    content(entry)
  }
}

渐隐动画

动画效果:

  1. 切换到新路由时:旧页面逐渐消失,新页面逐渐显现
  2. 回退到上一路由时:上述动画反过来
fun NavGraphBuilder.composableFaded(
  route: String,
  arguments: List<NamedNavArgument> = emptyList(),
  deepLinks: List<NavDeepLink> = emptyList(),
  content: @Composable (NavBackStackEntry) -> Unit
) {
  composable(route = route, arguments = arguments, deepLinks = deepLinks, enterTransition = {
    // 新页面:逐渐呈现(不透明度从 0 到 100%)
    fadeIn(animationSpec = tween(300))
  }, exitTransition = {
    // 旧页面:逐渐变淡消失(不透明度从 100% 到 0)
    fadeOut(animationSpec = tween(300))
  }, popEnterTransition = {
    // 返回时:新页面(实际上是旧页面)逐渐呈现(不透明度从 0 到 100%)
    fadeIn(animationSpec = tween(300))
  }, popExitTransition = {
    // 返回时:旧页面(实际上是新页面)逐渐变淡消失(不透明度从 100% 到 0)
    fadeOut(animationSpec = tween(300))
  }) { entry ->
    content(entry)
  }
}

滑动动画

该动画是作者个人最喜欢的一个动画,过渡流畅不拖沓,且具备灵动性

动画效果:

  1. 切换到新路由时:旧页面缩小渐变消失,新页面从右到左滑入界面并渐变显现
  2. 回退到上一路由时:上述动画反过来
fun NavGraphBuilder.composableSlide(
  route: String,
  arguments: List<NamedNavArgument> = emptyList(),
  deepLinks: List<NavDeepLink> = emptyList(),
  content: @Composable (NavBackStackEntry) -> Unit
) {
  composable(route = route, arguments = arguments, deepLinks = deepLinks, enterTransition = {
    // 新页面:从右到左滑入 + 渐变显示
    slideInHorizontally(initialOffsetX = { it }, animationSpec = tween(300)) + fadeIn(
      animationSpec = tween(300)
    )
  }, exitTransition = {
    // 旧页面:缩小消失 + 渐变消失
    scaleOut(targetScale = 0.8f, animationSpec = tween(300)) + fadeOut(animationSpec = tween(300))
  }, popEnterTransition = {
    // 返回时:新页面从小到大缩放 + 渐变显示
    scaleIn(initialScale = 0.8f, animationSpec = tween(300)) + fadeIn(animationSpec = tween(300))
  }, popExitTransition = {
    // 返回时:旧页面从左到右滑出 + 渐变消失
    slideOutHorizontally(targetOffsetX = { it }, animationSpec = tween(300)) + fadeOut(
      animationSpec = tween(300)
    )
  }) { entry ->
    content(entry)
  }
}

动画过渡实战

根据上面代码讲述,我们知道了路由切换的基本理论,包括如何封装我们的composable,并提供各种动画切换过渡效果,现在,我们需要将动画切换效果应用到实际场景中去;

其实使用方法很简单,您仅需在NavHost里面把原来的composable切换成您刚刚添加的动画composable即可;
比如下面我使用了滑动切换动画,它的代码是这样的:

  NavHost(modifier = modifier, navController = navController, startDestination = startDestination) {
    // 测试滑动过渡动画
    composableScale(route = NavAnimatePageRoutes.Scaled.route) {
      NavScaleAnimatePage(navController)
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhillerDev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值