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
相关产品推荐
相关产品推荐

