You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BottomNavigationView切换标签时如何避免使用导航栈的自定义动画?

BottomNavigationView + Navigation Component 标签切换动画异常修复方案

问题背景

使用bottomNavigation.setupWithNavController(this.navHostFragment.navController)配置底部导航与Navigation组件结合,底部导航包含两个标签页(tab1、tab2),每个标签对应独立的嵌套导航图,且标签内部通过带自定义滑动动画的action堆叠Fragment。当前问题为:当标签内存在Fragment堆叠时,切换标签会复用栈顶Fragment的action动画,而非标签切换的默认动画;替换R.animator下的nav_default_*默认动画仅对标签根Fragment生效。

已知问题说明

该问题是Google官方的已知Bug(编号194113170),表现为:使用BottomNavigationView结合Navigation组件时,若标签对应的导航栈存在Fragment堆叠,切换标签会错误应用栈顶Fragment的进入/退出动画,而非标签切换的默认动画。

临时修复方案

方案1:通过Destination监听重置动画

给NavController添加OnDestinationChangedListener,在导航到标签根页面时强制切换为默认标签动画,非根页面恢复自定义动画:

navController.addOnDestinationChangedListener { _, destination, _ ->
    val fragmentNavigator = navController.navigatorProvider.getNavigator(FragmentNavigator::class.java)
    val isTabRoot = listOf(R.id.tab1, R.id.tab2).contains(destination.id)
    if (isTabRoot) {
        // 应用标签切换的默认动画
        fragmentNavigator.apply {
            enterAnim = R.anim.nav_default_enter_anim
            exitAnim = R.anim.nav_default_exit_anim
            popEnterAnim = R.anim.nav_default_pop_enter_anim
            popExitAnim = R.anim.nav_default_pop_exit_anim
        }
    } else {
        // 恢复页面跳转的自定义滑动动画
        fragmentNavigator.apply {
            enterAnim = R.anim.slide_in_right
            exitAnim = R.anim.slide_out_left
            popEnterAnim = R.anim.slide_in_left
            popExitAnim = R.anim.slide_out_right
        }
    }
}

方案2:重写BottomNavigation导航逻辑

自定义扩展函数,在切换标签时临时替换动画,完成后恢复:

fun BottomNavigationView.setupWithNavControllerFix(navController: NavController) {
    this.setupWithNavController(navController)
    this.setOnItemSelectedListener { item ->
        val tabRootIds = listOf(R.id.tab1, R.id.tab2)
        if (item.itemId in tabRootIds) {
            val fragmentNavigator = navController.navigatorProvider.getNavigator(FragmentNavigator::class.java)
            // 保存当前动画配置
            val originalAnims = listOf(
                fragmentNavigator.enterAnim,
                fragmentNavigator.exitAnim,
                fragmentNavigator.popEnterAnim,
                fragmentNavigator.popExitAnim
            )
            // 临时设置标签切换默认动画
            fragmentNavigator.apply {
                enterAnim = R.anim.nav_default_enter_anim
                exitAnim = R.anim.nav_default_exit_anim
                popEnterAnim = R.anim.nav_default_pop_enter_anim
                popExitAnim = R.anim.nav_default_pop_exit_anim
            }
            // 执行标签导航
            navController.navigate(item.itemId)
            // 恢复原有动画配置
            fragmentNavigator.apply {
                enterAnim = originalAnims[0]
                exitAnim = originalAnims[1]
                popEnterAnim = originalAnims[2]
                popExitAnim = originalAnims[3]
            }
            true
        } else {
            NavigationUI.onNavDestinationSelected(item, navController)
        }
    }
}

使用时替换原配置代码:

bottomNavigation.setupWithNavControllerFix(this.navHostFragment.navController)

方案3:降级Navigation组件版本

可临时降级到Bug出现前的版本(如Navigation Component 2.3.0),但不推荐长期使用,建议优先等待官方修复。


内容的提问来源于stack exchange,提问作者rbrn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:53:23