BottomNavigationViewの下までコンテンツが割り込んでしまう問題 (Contents overlapping)

CoordinatorLayoutの中に、AppBarLayout、コンテンツのConstraintLayout、BottomNavigationView、を入れて、真ん中にコンテンツを配置したい場合。コンテンツにlayout_behaviorを設定するとAppBarはよけてくれますが、BottomNavigationは考慮してもらえません。

app:layout_behavior="@string/appbar_scrolling_view_behavior"

そこで、コンテンツの下にバーの高さ分のマージンが追加されるように、このクラスをカスタマイズします。

class AppBarWithBottomScrollingViewBehavior(context: Context, attrs: AttributeSet): AppBarLayout.ScrollingViewBehavior(context, attrs) {

    override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        return super.layoutDependsOn(parent, child, dependency) || dependency is BottomAppBar || dependency is BottomNavigationView
    }

    override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        super.onDependentViewChanged(parent, child, dependency)
        if (dependency is BottomAppBar || dependency is BottomNavigationView) {
            (child.layoutParams as? CoordinatorLayout.LayoutParams)?.let {
                if (it.bottomMargin != dependency.height) {
                    it.bottomMargin = dependency.height
                    child.requestLayout()
                    return true
                }
            }
        }
        return false
    }
}

自動的にマージンが追加されるので、レイアウト側でandroid:layout_marginは設定しないようにします。

このクラスを使ってもらえるようにstringsに設定します。

<string name="appbar_scrolling_view_behavior" translatable="false">com.example.myapplication.ui.main.AppBarWithBottomScrollingViewBehavior</string>

クラスはフルパスで指定しないとRuntimeExceptionでクラッシュしてしまいます。

java.lang.RuntimeException: Unable to start activity ComponentInfo: android.view.InflateException: Binary XML file in activity: Could not inflate Behavior subclass com.example.myapplication.debug.ui.main.AppBarWithBottomScrollingViewBehavior

これでバーの間にコンテンツが綺麗に挟まります。

このクラスは、コンテンツ部分がフラグメントの場合、BottomNavigationをBottomAppBarに入れて使う場合、のいずれも確認済みです。