Android Navigation框架下,Fragment控制宿主Activity中View显示隐藏:首次进入目标Fragment时View未隐藏的问题解决
我来帮你搞定这个首次进入SongDetailsFragment时bottom_controls还显示的问题!咱们先分析下当前实现的问题,再给你两个靠谱的解决方案。
问题根源
你当前的实现里,在Fragment的生命周期方法(比如onActivityCreated、onResume)里通过supportFragmentManager.currentNavigationFragment判断当前页面,但首次导航到SongDetailsFragment时,Fragment的生命周期方法执行时机可能早于导航完成的时机,此时currentNavigationFragment还没更新成当前的SongDetailsFragment,导致判断逻辑走了showMiniPlayer(),所以底部栏没隐藏。另外,currentFragment == this as SongDetailsFragment这个判断也有点多余,强转的写法完全没必要。
解决方案
方案一:用Navigation的导航监听器(推荐)
这是官方推荐的监听页面导航变化的方式,能准确捕获每一次导航完成的事件,不管首次还是后续进入都能可靠触发。
在MainActivity.kt的onCreate方法里添加导航监听器:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取NavController val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController // 添加导航目标变化监听器 navController.addOnDestinationChangedListener { _, destination, _ -> // 替换成你nav_graph里SongDetailsFragment的实际id if (destination.id == R.id.songDetailsFragment) { viewModel.hideMiniPlayer() } else { viewModel.showMiniPlayer() } } }
然后移除MainActivity和BaseSongDetailFragment里原来的显示/隐藏判断逻辑,这个监听器会自动处理所有导航场景:只要进入SongDetailsFragment就隐藏底部栏,离开就显示,逻辑清晰还解耦。
方案二:修复Fragment生命周期里的逻辑
如果不想用导航监听器,可以修改BaseSongDetailFragment的逻辑,改用更可靠的生命周期方法,并且直接基于当前Fragment类型判断:
open class BaseSongDetailFragment : Fragment() { private val songDetailViewModel by sharedViewModel<SongDetailViewModel>() protected val mainViewModel by inject<MainViewModel>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) showHideBottomSheet() } override fun onStop() { // 当Fragment停止(比如离开页面)时,显示底部栏 mainViewModel.showMiniPlayer() super.onStop() } private fun showHideBottomSheet() { val currentData = songDetailViewModel.currentData.value ?: return if (currentData.id == 0L) return // 当前就是SongDetailsFragment的父类,直接执行隐藏逻辑 mainViewModel.hideMiniPlayer() } }
这里用onViewCreated(视图创建完成后)触发隐藏,onStop(页面退出时)触发显示,避免了首次进入时的时机问题,而且不需要再判断currentFragment,逻辑更简洁。
额外提示
记得检查是否有重复的显示/隐藏逻辑(比如MainActivity里的原有判断),如果有要移除,避免逻辑冲突导致的异常。
内容的提问来源于stack exchange,提问作者ibramazin

