通过Fragment导航返回后Snackbar重叠Floating Action Button如何解决
问题根因
你当前代码的问题在于Snackbar的宿主视图选择错误:你在UpdateFragment中调用createSnackBar时传入的是UpdateFragment自身的根视图requireView(),Snackbar会顺着该视图向上查找最外层根布局作为附着节点,随后你立即执行导航操作,UpdateFragment的视图被销毁,Snackbar最终直接附着到Activity的Window DecorView上,和ListFragment里的CoordinatorLayout不存在从属关系,CoordinatorLayout感知不到该Snackbar的存在,自然不会触发Floating Action Button(以下简称FAB)的上移动画,导致重叠。
异常效果与预期效果对比如下:
- 当前异常效果:

- 预期正常效果:

可行解决方案
以下方案按推荐优先级排序:
方案1:Fragment结果回传,由ListFragment触发Snackbar(最推荐)
将操作成功的事件回传给ListFragment,由ListFragment使用自身内部的CoordinatorLayout作为Snackbar的宿主视图,此时CoordinatorLayout可正常识别Snackbar,自动触发FAB偏移。
代码实现
- UpdateFragment操作成功后,先发送结果再执行导航:
// UpdateFragment 操作成功后逻辑 setFragmentResult("operation_success", bundleOf("msg_res" to R.string.successfully_updated)) findNavController().navigate(R.id.action_updateFragment_to_listFragment)
- ListFragment的
onViewCreated中注册结果监听器,接收事件后创建Snackbar:
// ListFragment onViewCreated 中添加 setFragmentResultListener("operation_success") { _, bundle -> val messageRes = bundle.getInt("msg_res") // 传入ListFragment布局中的CoordinatorLayout实例作为宿主 createSnackBar(binding.coordinatorLayout, messageRes, Snackbar.LENGTH_SHORT) }
方案2:直接指定CoordinatorLayout作为Snackbar宿主
如果你的CoordinatorLayout和FAB都定义在Activity层级,可直接传入Activity中的CoordinatorLayout作为Snackbar的宿主:
// UpdateFragment 操作成功后逻辑 val activityCoordinator = requireActivity().findViewById<CoordinatorLayout>(R.id.activity_coordinator_id) createSnackBar(activityCoordinator, R.string.successfully_updated, Snackbar.LENGTH_SHORT) findNavController().navigate(R.id.action_updateFragment_to_listFragment)
方案3:手动控制FAB偏移(兜底方案)
如果以上方案都不适用,可通过Snackbar的展示/销毁回调手动控制FAB的位置:
改造createSnackBar函数:
fun createSnackBar(view: View, @StringRes message: Int, duration: Int, fab: FloatingActionButton? = null) { val resources = view.resources val snackBar = Snackbar.make(view, resources.getString(message), duration) fab?.let { targetFab -> snackBar.addCallback(object : Snackbar.Callback() { override fun onShown(sb: Snackbar?) { super.onShown(sb) sb?.view?.height?.let { height -> targetFab.animate().translationY(-height.toFloat()).setDuration(200).start() } } override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { super.onDismissed(transientBottomBar, event) targetFab.animate().translationY(0f).setDuration(200).start() } }) } snackBar.show() }
调用时传入FAB实例即可:
// ListFragment中调用时传入自身的FAB实例 createSnackBar(requireView(), R.string.successfully_updated, Snackbar.LENGTH_SHORT, binding.fab)
内容的提问来源于stack exchange,提问作者NTaveras
相关产品推荐
相关产品推荐

