在Android

时间:2015-11-05 09:47:56

标签: android navigation-drawer material-design androiddesignsupport navigationview

我有一个活动,它从支持库托管DrawerLayout和NavigationView。我将标题布局设置为导航视图,我希望导航标题高度为" wrap_content"。所以当我将高度设置为" wrap_content"标题布局位于状态栏后面。

我想要的结果是导航抽屉应该在状态栏后面绘制,但导航标题应该按状态栏高度向下推。

下面是我得到的截图。注意"登录"按钮位于状态栏后面。

screenshot

活动布局

<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>

导航视图标题布局

<?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>

我已经通过StackOverflow搜索了一个解决方案,但无法找到它。所以有人请说清楚。提前谢谢。

3 个答案:

答案 0 :(得分:9)

<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”

和CoordinatorLayout =&gt;机器人:fitsSystemWindows = “假”

答案 1 :(得分:3)

首先,请记住,您不能在棒棒糖之前绘制状态栏。

解决方案

对于Lollipop +,您应该将android:fitsSystemWindows="true"设置为DrawerLayout,而将NavigationView保留为默认值。

然后在设置标题后,在您的活动或片段上

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()
    }
}

说明

窗口正在将名为insets的对象(其尺寸分别为顶部,左侧,底部,右侧)传递到其子视图。带有fitSystemWindows=true的子视图将对此插图无效,并且可以将其发送给子视图。值为false的视图可以使用这些值为其自身添加额外的填充或边距。

fitSystemWindows=false中的NavigationView的设置不起作用,因为它正在使用插图对其自身施加额外的余量。您想要的是标题视图LinearLayout,以应用此边距。但是NavigationView中有两个中间容器视图,它们不会将插图传递到LinearLayout,因此您必须在这些容器之前拦截窗口插图,并自己应用标题视图的边距或填充

你永远不应该做的事

无论Android版本是什么,都不要假设窗口插入量将是固定值或从资源中获取它们。特定的设备具有特定的窗口插入值,有些具有较大的“缺口”以适合大型相机,有些制造商决定使其厚度小于Android建议的规格。

答案 2 :(得分:-1)

您使用COL2作为标题布局的根元素。 LinearLayoutFrameLayout等是忽略LinearLayout属性的基本布局。 我建议您使用android:fitsSystemWindows作为标题布局的根元素。CoordinatorLayout属性设置为CoordinatorLayout的{​​{1}}会自动调整其内部填充以防止其子元素被系统窗口(例如状态栏)重叠。

这些信息来自this article,“我为什么要适合SystemWindows?”伊恩湖(Ean Lake)

  

尽管基本布局(FrameLayout,LinearLayout等)使用默认行为,但是有许多布局已经自定义了它们对fitsSystemWindows的反应以适应特定用例。

     

...

     

CoordinatorLayout还利用了它处理窗口嵌入的方式,允许子视图上的Behavior设置在每个子视图本身调用dispatchApplyWindowInsets()之前,拦截并更改View对窗口嵌入的反应。它还使用fitsSystemWindows标志来了解是否需要绘制状态栏背景。

要实现所需的功能,请确保遵循以下布局结构。

布局/activity_xxxxx.xml

android:fitsSystemWindows

layout / nav_header.xml

true