【问题标题】:Android Draw behind Status bar but not behind the navigation barAndroid Draw 在状态栏后面但不在导航栏后面
【发布时间】:2016-01-26 02:04:02
【问题描述】:

我正在研究一种方式,使状态栏完全透明,而不是半透明,并且导航栏保持不变。

我能得到的最接近的是使用标志

WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS

但这也会在导航栏后面绘制。

背景使这个变得棘手,它是一个微妙的渐变,当我将状态栏颜色设置为渐变的开始时,它看起来几乎正确,但在屏幕顶部有一条微妙的线条。

有没有一种好方法可以让 Activity 适应窗口,只在顶部,但如果底部有导航栏,就不要管它了吗?

【问题讨论】:

    标签: android android-6.0-marshmallow android-statusbar android-navigation-bar


    【解决方案1】:

    一个好的方法是来自this answer 的方法一。

    要实现完全透明的状态栏,你必须使用 statusBarColor,仅适用于 API 21 及更高版本。 windowTranslucentStatus 在 API 19 及更高版本中可用,但它为状态栏添加了有色背景。但是,设置 windowTranslucentStatus 确实实现了将 statusBarColor 更改为透明的一件事:它设置了 SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 标志。获得相同效果的最简单方法是手动设置这些 标志,它有效地禁用了 Android 强加的插图 布局系统,让您自生自灭。

    您在 onCreate 方法中调用此行:

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

    请务必在 /res/values-v21/styles.xml 中设置透明度:

    <item name="android:statusBarColor">@android:color/transparent</item>
    

    或以编程方式设置透明度:

    getWindow().setStatusBarColor(Color.TRANSPARENT);
    

    这种方法的好处是相同的布局和设计 也可以通过交换透明状态栏在 API 19 上使用 用于有色半透明状态栏。

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

    我猜你已经尝试过这个或类似的东西。如果这不起作用,请确保您的根元素是 FrameLayout。

    【讨论】:

    • 默认为 android.support.design.widget.CoordinatorLayout 而不是框架布局。成功了,谢谢
    【解决方案2】:

    免责声明: 这是补充答案,因为接受的答案在 API 级别 30 之前有效且不被弃用,因为系统 自 API 级别 30 起,可见性标志已被弃用。

    setDecorFitsSystemWindows() 为您的应用实现edge-to-edge(即应用将扩展其内容以扩展到整个屏幕以覆盖系统状态栏和导航栏)

    这可以在活动中实现:

    WindowCompat.setDecorFitsSystemWindows(window, false)
    

    现在剩下的就是避免与系统导航栏重叠:

    As per documentation:

    您可以通过对插图做出反应来解决重叠问题,插图指定了哪些 屏幕的某些部分与导航等系统 UI 相交 栏或状态栏。相交可能意味着简单地显示 上面的内容,但它也可以通知你的应用程序关于系统 手势也是。

    所以,我们需要处理 API 级别 30+ 的插入,以避免应用与底部导航栏重叠:

    /*
    *  Making the Navigation system bar not overlapping with the activity
    */
    if (Build.VERSION.SDK_INT >= 30) {
    
        // Root ViewGroup of my activity
        val root = findViewById<ConstraintLayout>(R.id.root)
    
        ViewCompat.setOnApplyWindowInsetsListener(root) { view, windowInsets ->
    
            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
    
            // Apply the insets as a margin to the view. Here the system is setting
            // only the bottom, left, and right dimensions, but apply whichever insets are
            // appropriate to your layout. You can also update the view padding
            // if that's more appropriate.
    
            view.layoutParams =  (view.layoutParams as FrameLayout.LayoutParams).apply {
                leftMargin = insets.left
                bottomMargin = insets.bottom
                rightMargin = insets.right
            }
    
            // Return CONSUMED if you don't want want the window insets to keep being
            // passed down to descendant views.
            WindowInsetsCompat.CONSUMED
        }
    
    }
    

    Check documentation 了解更多信息。

    加分:

    • 如果您打算将&lt;item name="android:windowTranslucentStatus"&gt;true&lt;/item&gt; 用于较低的API 级别,那么您必须覆盖API-30 中的主题/样式;即有一个默认样式的res\values-v30\themes.xml(当然没有windowTranslucentStatus)

    【讨论】:

    • 有没有办法使用 WindowCompat 的这个新方法只在状态栏后面绘制?正如您所提到的,这目前使应用程序在状态栏和导航栏后面绘制。
    • @vepzfe 你能在答案ViewCompat.setOnApplyWindowInsetsListener 中添加这段代码吗,这将使它在底部导航栏上方绘制......还要确保你没有添加`topMargin = insets .top` 使其不会在状态栏上绘制
    • 也请查看this answer;还有更详细的
    • 感谢您的链接。所以简而言之,避免在导航栏后面绘制的唯一方法是使用插图并设置底部边距,因为没有办法告诉系统不要在那里绘制应用程序。
    • 我明白了。我现在知道了。诚然,旧的弃用代码仍然有效。我之所以要为系统寻找一种方法,是因为我的特定活动的布局非常复杂,有多个底部工作表,因此设置底部边距不起作用,并且需要在布局中进行大量更改。因此,直到我能找到更好的解决方案,使用旧的弃用标志。我尝试为装饰视图和 decorView.rootView 甚至使用 window.attributes 的窗口设置下边距,但这些都不起作用。
    猜你喜欢
    • 1970-01-01
    • 2018-01-17
    • 2018-01-13
    • 2015-01-10
    • 1970-01-01
    • 2021-11-08
    • 2013-10-04
    • 2016-10-08
    • 1970-01-01
    相关资源
    最近更新 更多