在 Android 中将状态栏填充设置为 NavigationView
Posted
技术标签:
【中文标题】在 Android 中将状态栏填充设置为 NavigationView【英文标题】:Setting Statusbar padding to NavigationView in Android 【发布时间】:2016-02-06 02:12:17 【问题描述】:我有一个活动,它承载来自支持库的 DrawerLayout 和 NavigationView。我正在为导航视图设置标题布局,并且我希望导航标题高度为“wrap_content”。因此,当我将高度设置为“wrap_content”时,标题布局位于状态栏后面。
我想要的结果是导航抽屉应该在状态栏后面绘制,但导航标题应该被状态栏高度向下推。
下面是我得到的截图。请注意状态栏后面的“登录”按钮。
活动布局
<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_
android:layout_
android:id="@+id/nav_drawer"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:layout_
android:layout_>
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior"></android.support.v4.view.ViewPager>
<android.support.design.widget.AppBarLayout
android:layout_
android:layout_>
<include layout="@layout/include_toolbar"/>
<android.support.design.widget.TabLayout
app:theme="@style/ThemeOverlay.AppCompat.Dark"
style="@style/MyCustomTabLayout"
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
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_
android:layout_
android:id="@+id/text_user_name"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
<TextView
android:visibility="gone"
android:layout_
android:layout_
android:id="@+id/text_email"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
<Button
android:id="@+id/button_sign_in"
android:layout_
android:layout_
android:text="Sign In"/>
</LinearLayout>
我已通过 *** 搜索解决方案,但找不到。所以有人请阐明一下。提前致谢。
【问题讨论】:
【参考方案1】:<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_
android:layout_
app:headerLayout="@layout/nav_header"
app:menu="@menu/menu_navigation"
android:fitsSystemWindows="false"
android:layout_gravity="start"/>
android:fitsSystemWindows="false"
和 CoordinatorLayout => android:fitsSystemWindows="false"
【讨论】:
您好,如果您能围绕您的解决方案提供更多解释,那就太好了。 (提示:人们也更有可能接受您的解决方案;)) 这将导致抽屉被绘制在状态栏下方,这不是我们想要的行为。 @SpaceBison 这是想要的行为。这也是 标准 行为。关键是,op 希望 button 不显示在状态栏下方。例如,通过在其顶部添加填充。【参考方案2】:首先,请记住,您不能在 Lollipop 之前在状态栏后面绘图。
解决方案
对于 Lollipop+,您应该为 DrawerLayout
设置 android:fitsSystemWindows="true"
并为 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 的视图可能会使用这些值为其自身添加额外的填充或边距。
NavigationView
的设置fitSystemWindows=false
不起作用,因为它使用插图为其自身应用额外的边距。你想要的是你的标题视图LinearLayout
来应用这个边距。但是NavigationView
内部有两个中间容器视图,它们不会将插图传递给您的LinearLayout
,因此您必须在这些容器之前截取窗口插图并自己应用页眉视图的边距或填充。
你不应该做的事情
永远不要假设窗口插图是固定值或从资源中获取它们,无论 Android 版本是什么。特定设备具有特定的窗口嵌入值,有些设备具有较厚的“凹口”以适合大型相机,有些制造商决定使其比 Android 推荐的规格更薄。
【讨论】:
【参考方案3】:您使用LinearLayout
作为标题布局的根元素。 FrameLayout
、LinearLayout
等是忽略android:fitsSystemWindows
属性的基本布局。 我建议您使用 CoordinatorLayout
作为标题布局的根元素。 使用 CoordinatorLayout
并将其 android:fitsSystemWindows
属性设置为 true
将自动调整其内部填充以防止其子元素被与状态栏等系统窗口重叠。
这些信息来自this article,“我为什么要适应SystemWindows?”伊恩莱克。
虽然基本布局(FrameLayout、LinearLayout 等)使用默认行为,但有许多布局已经自定义了它们对 fitSystemWindows 的反应方式以适应特定用例。
...
CoordinatorLayout 还利用覆盖它处理窗口插入的方式,允许子视图上设置的行为拦截和更改视图对窗口插入的反应,然后再对每个子视图调用 dispatchApplyWindowInsets()。它还使用 fitSystemWindows 标志来了解是否需要绘制状态栏背景。
要实现您想要的,请确保遵循此布局结构。
布局/activity_xxxxx.xml
<android.support.v4.widget.DrawerLayout
...
android:fitsSystemWindows="true">
<!-- content -->
...
<!-- drawer -->
<android.support.design.widget.NavigationView
...
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header" />
<android.support.v4.widget.DrawerLayout>
布局/nav_header.xml
<android.support.design.widget.CoordinatorLayout
...
android:fitsSystemWindows="true">
<!-- content -->
...
<android.support.design.widget.CoordinatorLayout>
【讨论】:
以上是关于在 Android 中将状态栏填充设置为 NavigationView的主要内容,如果未能解决你的问题,请参考以下文章
Android 主题:在 Material3 中将状态栏颜色设置为操作栏颜色