I'm trying to use a CoordinatorLayout
with a BottomNavigationView
, an AppBarLayout
, and a ViewPager
. Here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="@menu/navigation"/>
</android.support.design.widget.CoordinatorLayout>
The problem is that the CoordinatorLayout
places the ViewPager
to extend to the bottom of the screen, so the bottom is obscured by the BottomNavigationView
, like this:
This happens even though the CoordinatorLayout
itself doesn't extend down so far:
I've tried adding app:layout_insetEdge="bottom"
to the BottomNavigationView
and app:layout_dodgeInsetEdges="bottom"
to the ViewPager
, but that has a different problem: it shifts the bottom of the ViewPager
up, but it keeps the same height, so the top is now chopped off:
I tried two other experiments. First, I tried removing the BottomNavigationView
from the CoordinatorLayout
and making them siblings under a vertical LinearLayout
. Second, I put the ViewPager
and BottomNavigationView
together under a LinearLayout
, hoping they would layout out correctly. Neither helped: in the first case, the CoordinatorLayout
still sized the ViewPager
with respect to the entire screen, either hiding part of it behind the BottomNavigationView
or chopping off the top. In the second case, the user needs to scroll to see the BottomNavigationView
.
How do I get the layout right?
P.S. When I tried the layout suggested by @Anoop S S (putting the CoordinatorLayout
and the BottomNavigationView
as siblings under a RelativeLayout
), I get the following (with the ViewPager
still extending down behind the BottomNavigationView
):
As before, the CoordinatorView
itself only extends down to the top of the BottomNavigationView
.
I came up with a different approach (not battle tested yet though):
I subclassed AppBarLayout.ScrollingViewBehavior
to adjust the bottom margin of the content view based on the height of the BottomNavigationView
(if present). This way it should be future proof (hopefully) if the height of the BottomNavigationView
changes for any reason.
The subclass (Kotlin):
class ScrollingViewWithBottomNavigationBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
// We add a bottom margin to avoid the bottom navigation bar
private var bottomMargin = 0
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
return super.layoutDependsOn(parent, child, dependency) || dependency is BottomNavigationView
}
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
val result = super.onDependentViewChanged(parent, child, dependency)
if(dependency is BottomNavigationView && dependency.height != bottomMargin) {
bottomMargin = dependency.height
val layout = child.layoutParams as CoordinatorLayout.LayoutParams
layout.bottomMargin = bottomMargin
child.requestLayout()
return true
} else {
return result
}
}
}
And then in the layout XML you put:
app:layout_behavior=".ScrollingViewWithBottomNavigationBehavior"
instead of
app:layout_behavior="@string/appbar_scrolling_view_behavior"