开关状态栏文本颜色/设置外观WindowController的LightStatusBars未按预期工作

人气:54 发布:2023-01-03 标签: android statusbar android-navigation-bar android-window android-api-30

问题描述

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

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

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

这是使用过的控制器,在MainActivityonCreate()中创建

windowController = new WindowInsetsControllerCompat(this.getWindow(), this.getWindow().getDecorView());
在这里您可以看到状态栏是绿色的,因为mainActivity的背景位于透明状态栏的后面。此版本的windowController.setAppearanceLightStatusBars(true);已注释

在这里,您可以看到状态栏是白色的,文本是白色的(因为它仍然是绿色背景),但它被下移了,并被某种默认的白色状态栏背景所取代。看看电池图标现在在哪里。windowController.setAppearanceLightStatusBars(true);未被注释,并在路上的某个地方被执行

更新:

遵循this我能够在运行Android 10的测试设备上获得所需结果。

在运行API 30的模拟器上,我现在又遇到了一个问题:

WindowCompat.setDecorFitsSystemWindows(window, false);

让我们在状态栏后面,也在导航栏后面。现在,状态栏按预期工作,但导航栏隐藏了部分用户界面。我需要导航栏处于旧状态,不要被拖到下面。有什么想法吗?

为完整性

compileSdkVersion 31
minSdkVersion 23
targetSdkVersion 31

推荐答案

跟随this我能够在测试中获得预期的结果 运行Android 10的设备。

在运行API 30的模拟器上,我现在又遇到了一个问题:

WindowCompat.setDecorFitsSystemWindows(window, false);

让我们在状态栏后面,也在导航栏后面。 现在,状态栏按预期工作,但导航栏隐藏了部分 用户界面的。我需要导航栏保持其旧状态,而不是 被画在下面。有什么想法吗?

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

但是,As per documentation:

您可以通过对插页做出反应来处理重叠,插页指定了 屏幕的某些部分与系统用户界面相交,如导航 栏或状态栏。相交可以简单地表示显示 在内容之上,但它还可以通知您的应用程序有关系统的信息 手势也一样。

因此,我们需要处理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
    }

}

17