android - 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
解决方案
在此之后,我能够在运行 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
}
}
推荐阅读
- sql - 如何根据参数使 WHERE 子句中的谓词可选
- python - Python C API 中的 PyCompilerFlags 是什么?
- javascript - 如何在 React 的表单中动态添加字段
- r - 在大小图例 geom_point ggplot2 中显示所有形状
- javascript - React-Native 函数的区别
- sql-server - SQL Server:存储过程的语法错误
- sql - 插入选择 * - 覆盖某些列
- node.js - TypeError:无法读取未定义的属性“子字符串”
- scala - 通过 Scala 发送邮件
- powershell - 在 Powershell 中恢复 Clear-Host 命令