Android 在状态栏后面绘制,但不在导航栏后面绘制

Android Draw behind Status bar but not behind the navigation bar

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

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

WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS

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

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

有什么好的方法可以让 activity 适合 window,只在顶部,但如果底部有导航栏,不用管它吗?

一个好的方法是 中的方法一。

To achieve a completely transparent status bar, you have to use statusBarColor, which is only available on API 21 and above. windowTranslucentStatus is available on API 19 and above, but it adds a tinted background for the status bar. However, setting windowTranslucentStatus does achieve one thing that changing statusBarColor to transparent does not: it sets the SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flags. The easiest way to get the same effect is to manually set these flags, which effectively disables the insets imposed by the Android layout system and leaves you to fend for yourself.

You call this line in your onCreate method:

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

Be sure to also set the transparency in /res/values-v21/styles.xml:

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

Or set the transparency programmatically:

getWindow().setStatusBarColor(Color.TRANSPARENT);

The good side to this approach is that the same layouts and designs can also be used on API 19 by trading out the transparent status bar for the tinted translucent status bar.

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

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

Disclaimer: This is complementary answer as the accepted answer is valid without deprecation > till API level 30 because the system visibility flags are deprecated as of API level 30.

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

这可以在 activity 中实现:

WindowCompat.setDecorFitsSystemWindows(window, false)

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

As per documentation:

You can address overlaps by reacting to insets, which specify which parts of the screen intersect with system UI such as the navigation bar or the status bar. Intersecting can mean simply being displayed above the content, but it can also inform your app about system gestures, too.

因此,我们需要处理 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 了解更多信息。

加分:

  • 如果您要使用 <item name="android:windowTranslucentStatus">true</item> 用于较低的 API 级别,那么您必须覆盖 API-30 中的 themes/styles;即具有默认样式的 res\values-v30\themes.xml(当然没有 windowTranslucentStatus