首页 > 解决方案 > WindowController 的切换状态栏文本颜色/setAppearanceLightStatusBars 未按预期工作

问题描述

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

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

<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);
        }
}

这是使用的控制器,创建于onCreate()我的MainActivity

windowController = new WindowInsetsControllerCompat(this.getWindow(), this.getWindow().getDecorView());

在这里您可以看到状态栏是绿色的,因为 mainActivity 的背景位于半透明状态栏的后面。windowController.setAppearanceLightStatusBars(true);评论了这个版本 工作版本

在这里,您看到状态栏是白色的,文本是白色的(因为它仍然是绿色背景),但它被向下移动并被某种默认的白色状态栏背景取代。查看电池图标现在的位置。windowController.setAppearanceLightStatusBars(true);未发表评论并在沿路某处被处决 破解版

更新:

之后,我能够在运行 Android 10 的测试设备上获得所需的结果。

在 Emulator Running API 30 上,我现在还有一个问题:

WindowCompat.setDecorFitsSystemWindows(window, false);

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

为了完整性

compileSdkVersion 31
minSdkVersion 23
targetSdkVersion 31

标签: androidstatusbarandroid-navigation-barandroid-windowandroid-api-30

解决方案


之后,我能够在运行 Android 10 的测试设备上获得所需的结果。

在 Emulator Running API 30 上,我现在还有一个问题:

WindowCompat.setDecorFitsSystemWindows(window, false);

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

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

但是,根据文档:

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

因此,我们需要处理 API 级别 30+ 的系统栏插入,以避免您的应用与导航栏重叠:

这需要您的活动布局的顶级根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
    }

}

推荐阅读