在状态和导航栏后面显示内容

Posted

技术标签:

【中文标题】在状态和导航栏后面显示内容【英文标题】:Showing content behind status and navigation bar 【发布时间】:2018-01-13 14:21:16 【问题描述】:

这看起来像是一个重复的问题,但我做不到。我想要完全透明(不是半透明)的状态栏以及导航栏,并希望内容出现在它们后面。

activity_details.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 
    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_
    android:layout_
    android:background="@color/colorPrimary"
    tools:context="com.bitspilanidvm.bosm2017.DetailsActivity">

<ImageView
    android:layout_
    android:layout_
    android:src="@drawable/q"
    android:scaleType="centerCrop"/>

</LinearLayout>

v21 样式.xml

<resources>

<!-- Theme for API level > 21 -->
<style name="AppTheme" parent="AppBaseTheme">
     <!--Customize your theme here. -->
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:navigationBarColor">@android:color/transparent</item>
</style>

在活动java文件中

getWindow().getDecorView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
               View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        );

这就是我得到的。

如何获取导航栏后面的内容?

如果我添加

<item name="android:windowTranslucentNavigation">true</item>

到我的styles.xml

这是我得到的

如您所见,内容位于导航栏后面,但导航栏必须是半透明的。

有什么解决办法吗?

【问题讨论】:

这个设备没有硬后退按钮吗? 【参考方案1】:

在窗口中添加FLAG_LAYOUT_NO_LIMITS 标志。这适用于 Android KitKat 及更高版本的 API。示例如下:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
        Window window = getWindow(); 
     window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
    

FLAG_FULLSCREEN 不起作用的原因仅仅是因为 FULLSCREEN 标志用于删除状态栏等屏幕装饰(适用于您)。但是导航栏不是屏幕装饰。 LAYOUT_NO_LIMIT 标志允许窗口超出屏幕限制,因此导航栏也被此标志覆盖。

您还可以通过将应用设置为沉浸式模式来简单地隐藏导航和状态栏。

编辑 API ViewCompat.setOnApplyWindowInsetListener 解决了 android:fitsSystemWindows=”true” 无法解决的问题,并且窗口插图可以应用于特定视图。一个例子。

ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> 
    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
    params.topMargin = insets.getSystemWindowInsetTop();
    return insets.consumeSystemWindowInsets();
);

FrameLayoutLinearLayoutRelativeLayout 等标准布局不会将窗口插图传递给其子级,而材质布局则可以(例如 DrawerLayoutCoordinatorLayout )。所以我们可以将我们的布局更改为任何材质,或者我们可以子类化一个标准布局并自己将 insets 传递给布局的子级。我们只需要覆盖onApplyWindowInsets 方法。

@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) 
    int childCount = getChildCount();
    for (int index = 0; index < childCount; ++index)
        getChildAt(index).dispatchApplyWindowInsets(insets); 
        // let children know about WindowInsets

    return insets;

参考文档:OnApplyWindowInsetsListener、WindowInsets

【讨论】:

谢谢!它工作得很好。你能简要解释一下为什么会这样吗?为什么将装饰视图系统 ui 可见性标志设置为 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 不起作用? FLAG_FULLSCREEN 不起作用的原因仅仅是因为 FULLSCREEN 标志用于删除状态栏等屏幕装饰(对您有用)。但是导航栏不是屏幕装饰。 LAYOUT_NO_LIMIT 标志允许窗口超出屏幕限制,因此导航栏也被此标志覆盖。 这行得通!但现在的问题是窗口从不应用插图,所以我无法知道状态栏和导航栏在哪里(不使用一些 hacky 解决方法)。关于我们如何在onApplyWindowInsets() 中接收插图的任何线索? @Bryan 我不明白你的问题。应用上述代码后,状态和导航栏是透明的。您可以将插图应用于任何特定视图。 FrameLayoutLinearLayout 等布局不会将窗口插图传递给它们的子级,而材质布局(DrawerLayoutCoordinatorLayout)可以。我已经编辑了答案并添加了关于插图的内容。但我对你的问题还是含糊其辞。【参考方案2】:

我想评论接受的答案,但我还不能。

只是为了警告所有会采取这种方法的人

FLAG_LAYOUT_NO_LIMITS 让您将根视图扩展到屏幕边界之外,从而为您的布局设计带来其他问题。例如,此标志通过强制系统忽略“adjustPan”和“adjustResize”标志来简单地破坏表单的可读性

所以,即使我仍然认为 Ahbi 的答案是正确的,但请确保没有任何内容超出此标志的范围

更好的解决方案:

实际上,我刚刚找到了一种更好的方法来实现相同的结果,而不会破坏任何东西

这是我的样式文件

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:navigationBarColor">@android:color/transparent</item>

</style>

这些是我以编程方式设置的标志

w.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
w.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

设置标志 LAYOUT_HIDE_NAVIGATION(与样式项结合)起到了作用,我的表单仍然对 adjustPan 标志作出反应

【讨论】:

在回答这个问题时,我没有考虑过像adjustPan 这样的其他标志。谢谢指正。【参考方案3】:

如果您希望图像显示在状态栏后面

getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

但是这样做,fitsSystemWindows="true" 不起作用 工具栏与状态栏重叠。

【讨论】:

以上是关于在状态和导航栏后面显示内容的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Flutter 应用在​​ android 导航栏后面绘制并使导航栏完全透明?

移动开发中导航栏和搜索栏在设计中应该注意哪些问题?

移动设备上的引导导航栏显示在其他所有内容的后面

Android 显示、隐藏状态栏和导航栏

Android Draw 在状态栏后面但不在导航栏后面

Android 将App的内容延伸到状态栏/导航栏