切换状态栏文本颜色/WindowController 的 setAppearanceLightStatusBars 未按预期工作

Switch Status Bar Text Color / setAppearanceLightStatusBars of WindowController is not working as expected

我为我的应用程序使用了两种不同的背景,具体取决于哪个屏幕处于活动状态。一般来说,状态栏是透明的,背景应该放在它后面。根据背景,我需要状态栏文本的颜色为浅色或深色。

到目前为止,我使用这个主题属性使状态栏透明(它确实是半透明的,但如果有人知道如何让它透明,我们将不胜感激)

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

我正在使用 Jetpack 导航来导航并将参数传递到目的地,只要背景应该像这样切换

mNavController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        if (arguments != null) {
            setUseSecondaryBackground(arguments.getBoolean("bg_line_style", false));
        }
});

这真的很好用。现在不起作用的部分是状态栏文本颜色的切换:

private void setUseSecondaryBackground(boolean useLineBackground) {
        if (useLineBackground) {
            //Stuff to switch backgrounds
            windowController.setAppearanceLightStatusBars(false); //Works fine
        } else {
            //Stuff to switch backgrounds

            //Does not work!!! If enabled the whole background is shifted downward by the status bar hight - see pictures
            windowController.setAppearanceLightStatusBars(true);
        }
}

这是使用过的控制器,在我的 MainActivity

onCreate() 中创建
windowController = new WindowInsetsControllerCompat(this.getWindow(), this.getWindow().getDecorView());

在这里你看到状态栏是绿色的,因为mainActivity的背景位于半透明的状态栏后面。 windowController.setAppearanceLightStatusBars(true); 对此版本进行了评论

在这里你看到状态栏是白色的,文本是白色的(因为它仍然是绿色背景)但是它被向下移动并被某种默认的白色状态栏背景所取代。查看电池图标现在的位置。 windowController.setAppearanceLightStatusBars(true); 没有评论,在路上的某个地方被处决

更新:

之后,我能够在我的测试设备上获得想要的结果 运行 Android 10.

在模拟器上 运行 API 30 我现在还有一个问题:

WindowCompat.setDecorFitsSystemWindows(window, false);

让我们在状态栏后面和导航栏后面绘制。现在状态栏按预期工作,但导航栏隐藏了 UI 的一部分。我需要处于旧状态的导航栏,而不是在其下绘制。有什么想法吗?

完整性

compileSdkVersion 31
minSdkVersion 23
targetSdkVersion 31

Following I was able to get the desired result on my testing device running Android 10.

On the Emulator Running API 30 I now have one additional Problem:

WindowCompat.setDecorFitsSystemWindows(window, false);

lets us draw behind the status bar but also behind the navigation bar. Now the status bar works as intended but the navigation bar hides part of the UI. I need the navigation bar in its old state and not to be drawn under. Any ideas?

这是正确的,因为 setDecorFitsSystemWindows() 为您的应用实现了边到边(即应用将覆盖系统状态和导航栏)

但是,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+ 的系统栏插入,以避免您的应用与导航栏重叠:

这需要 activity 布局的顶层根 ViewGroup,因此您需要适当地转换 LayoutParams

这里我用的是FrameLayout.LayoutParams:

/*
*  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
    }

}