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

Navigation Component+Bottom Navigation View切换标签时Fragment入场动画重复触发问题

解决Tab切换时栈顶Fragment重复触发入场动画的方案

核心原因

每个Tab对应独立NavGraph,切换Tab时,对应NavHostFragment会重新attach其管理的Fragment栈,栈顶Fragment的onCreateAnimation方法被再次调用,导致自定义入场动画重复触发。


1. 自定义NavHostFragment控制动画触发

重写NavHostFragment,通过标记区分是Tab切换还是内部导航,仅在内部导航时应用动画:

class CustomNavHostFragment : NavHostFragment() {
    private var isTabSwitchTriggered = false

    override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
        return if (isTabSwitchTriggered) {
            isTabSwitchTriggered = false
            null // Tab切换时跳过动画
        } else {
            super.onCreateAnimation(transit, enter, nextAnim)
        }
    }

    // 外部调用标记Tab切换操作
    fun markAsTabSwitch() {
        isTabSwitchTriggered = true
    }
}

2. 改造BottomNavigationView切换逻辑

在Activity中监听Tab选中事件,切换前给目标NavHost标记Tab切换状态:

// 初始化时将每个Tab的NavHostFragment添加到FragmentManager并隐藏,仅显示默认Tab
val navHostMap = mapOf(
    R.id.tab1 to CustomNavHostFragment.create(R.id.nav_graph_tab1),
    R.id.tab2 to CustomNavHostFragment.create(R.id.nav_graph_tab2),
    // 其他Tab的NavHostFragment
)

navHostMap.values.forEach { fragment ->
    supportFragmentManager.beginTransaction()
        .add(R.id.nav_host_container, fragment, fragment.id.toString())
        .hide(fragment)
        .commit()
}

// 默认显示第一个Tab
supportFragmentManager.beginTransaction().show(navHostMap[R.id.tab1]!!).commit()

// Tab切换监听
bottomNavigationView.setOnItemSelectedListener { item ->
    val currentNavHost = supportFragmentManager.fragments.find { it.isVisible } as? CustomNavHostFragment
    val targetNavHost = navHostMap[item.itemId]!!
    
    // 标记目标NavHost即将进行Tab切换
    targetNavHost.markAsTabSwitch()

    // 切换显示/隐藏
    supportFragmentManager.beginTransaction()
        .hide(currentNavHost!!)
        .show(targetNavHost)
        .commit()
    true
}

3. 精细化配置NavGraph动画

仅在NavGraph内部的路由跳转上配置自定义动画,不要给Fragment设置全局默认动画:

<!-- nav_graph_tab1.xml -->
<action
    android:id="@+id/action_fragment1_to_fragment2"
    app:destination="@id/fragment2"
    app:enterAnim="@anim/slide_in_right"
    app:exitAnim="@anim/slide_out_left"
    app:popEnterAnim="@anim/slide_in_left"
    app:popExitAnim="@anim/slide_out_right"/>

<action
    android:id="@+id/action_fragment2_to_fragment3"
    app:destination="@id/fragment3"
    app:enterAnim="@anim/slide_in_right"
    app:exitAnim="@anim/slide_out_left"
    app:popEnterAnim="@anim/slide_in_left"
    app:popExitAnim="@anim/slide_out_right"/>

4. 确保NavHostFragment复用

避免每次切换Tab时重新创建NavHostFragment,Activity启动时一次性初始化所有Tab的NavHost,切换时仅做show/hide操作,减少Fragment的重新attach触发。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 12:45:37