Search code examples
androidandroid-architecture-navigationmaterial-components-android

Can't get proper behavior for transparent system bars + FAB + BottomNavigationView + SnackBar


I've seen solutions for various combinations of up to three of these things, but not all four at once.

Desired behavior is that the FAB sits above the BottomNavigationView, and if a SnackBar appears, it pushes the FAB up and appears above the BottomNavigationView.

What I've tried:

  1. BottomNavigationView and FAB are both in the CoordinatorLayout. The FAB is anchored to the BottomNavigationView so it can sit above it. To make the SnackBar appear above the BottomNavigationView instead of in front of it, it uses it as an anchor via setAnchorView, but this causes it not to push the FAB.

  2. BottomNavigationView sits below the CoordinatorLayout using a LinearLayout. The FAB has no anchor, so the SnackBar can push it. But when the SnackBar appears, it slides up way too far. It is trying to dodge the bottom window insets, but it is assuming the CoordinatorLayout is aligned to the bottom of the screen.

  3. To solve number 2, I tried putting a zero-height View at the bottom of the CoordinatorLayout and setting that as the SnackBar's anchor before showing it. From looking at the source code of SnackBar's behavior, this seems to be the only way to get it to ignore window insets. But when the SnackBar is anchored to something, it won't push the FAB. (same issue as number 1)

I saw this answer where they say it was resolved, such that you would think number 1 above would work, but that is with a BottomAppBar, not a BottomNavigationBar, which doesn't have any behaviors for interacting with FABs.

Incidentally, BottomNavigationView also seems to insist on adjusting its padding for window insets regardless of the fitsSystemWindows setting, so the layout of number 2 is much preferable for this reason.


Solution

  • Here is why FloatingActionButtons doesn't automatically dodge the SnackBar when the SnackBar has an anchor. CoordinatorLayout handles pushing the FloatingActionButton if a view is added that has the insetEdge of its LayoutParams set to Gravity.BOTTOM. SnackBar (actually its superclass) automatically sets the insetEdge to Gravity.BOTTOM, but only if it has no anchor view.

    So the solution to this is to manually set the inset edge when you are creating a SnackBar that has an anchor on the bottom:

    Snackbar.make(binding.coordinatorLayout, text, duration)
        .apply {
            anchorView = binding.bottomEdgeAnchor
            (view.layoutParams as CoordinatorLayout.LayoutParams).insetEdge = Gravity.BOTTOM
            show()
        }
    

    Then I follow option 3 in the original question.