I have an activity which hosts a DrawerLayout and NavigationView from support library. I'm setting a header layout to the navigation view and I want the navigation header height to be "wrap_content". So when I set the height to "wrap_content" the header layout goes behind the status bar.
The result I want is that the navigation drawer should draw behind the status bar but the navigation header should be pushed down by the statusbar height.
Below is the screenshot of what I am getting. Note the "SIGN IN" button going behind the status bar.
Activity layout
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nav_drawer"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"></android.support.v4.view.ViewPager>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/include_toolbar"/>
<android.support.design.widget.TabLayout
app:theme="@style/ThemeOverlay.AppCompat.Dark"
style="@style/MyCustomTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tabs"
/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:headerLayout="@layout/nav_header"
app:menu="@menu/menu_navigation"
android:fitsSystemWindows="true"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
Navigation View Header Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimaryDark"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:fitsSystemWindows="true"
android:gravity="bottom">
<TextView
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/text_user_name"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
<TextView
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/text_email"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
<Button
android:id="@+id/button_sign_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sign In"/>
</LinearLayout>
I've searched through StackOverflow for a solution but couldn't find it. So someone please shed some light. Thanks in advance.
Go to Settings -> Display -> Advanced -> Device Theme The desired padding should be back again.
com.google.android.material.navigation.NavigationView. Represents a standard navigation menu for application. The menu contents can be populated by a menu resource file. NavigationView is typically placed inside a DrawerLayout .
The user can view the navigation drawer when the user swipes a finger from the left edge of the activity. They can also find it from the home activity by tapping the app icon in the action bar. The drawer icon is displayed on all top-level destinations that use a DrawerLayout.
First, remember that you cannot draw behind status bar before Lollipop.
For Lollipop+, you should set the android:fitsSystemWindows="true"
for DrawerLayout
and leave the default for NavigationView
.
Then on your activity or fragment after setting the header:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
navigationView.setOnApplyWindowInsetsListener { v, insets ->
val header = navigationView.getHeaderView(0)
header.setPadding(
header.paddingLeft,
header.paddingTop + insets.systemWindowInsetTop,
header.paddingRight,
header.paddingBottom
)
insets.consumeSystemWindowInsets()
}
}
The window is passing a object called insets
(with dimensions for top, left, bottom, right) to it's childs views. The child views that have the fitSystemWindows=true
will do nothing with this insets and may send it forward to its children. The views that have it false may use the values to add extra padding or margin to itself.
Set fitSystemWindows=false
of the NavigationView
is not working because it is using the insets to apply extra margin to itself. What you want is your header view LinearLayout
to apply this margin. But there is two intermediate container views inside NavigationView
that will not pass forward the insets to your LinearLayout
, so you have to intercept the windows inset before these containers and apply yourself the margin or padding of your header view.
Never assume that the window insets will be a fixed value or get them from resources, no matter what the Android version is. Specific devices have specific values for window insets, some have thicker "notches" to fit big cameras, some manufacturers decide to make it thinner than Android recommended specs.
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:headerLayout="@layout/nav_header"
app:menu="@menu/menu_navigation"
android:fitsSystemWindows="false"
android:layout_gravity="start"/>
android:fitsSystemWindows="false"
and CoordinatorLayout => android:fitsSystemWindows="false"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With