[英]Android M Light and Dark status bar programmatically - how to make it dark again?
在 Android M 中,我们可以使状态栏图标变暗。 为此,我们可以在主题的 xml 中指定属性:
<item name="android:windowLightStatusBar">true</item>
或者我们在运行时用这段代码设置它:
View someView = findViewById(R.id.some_view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
someView.setSystemUiVisibility(someView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
它实际上工作正常。 但问题是如何在运行时正确地将状态栏模式设置为暗?
我已经尝试过这些变体:
// Makes status bar mode dark, but also hides it along with all navigation views.
someView.setSystemUiVisibility(someView.getSystemUiVisibility() | ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
// Does nothing
someView.setSystemUiVisibility(someView.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
// Also does nothing
someView.setSystemUiVisibility(someView.getSystemUiVisibility() ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
那么如何以正确的方式完成呢?
@Aracem 发布的解决方案是有效的,但是如果您尝试更改状态栏的背景颜色,则不起作用。 就我而言,我按以下方式进行操作。
要启用 windowLightStatusBar(以编程方式,例如在 Utils 类中):
public static void setLightStatusBar(View view,Activity activity){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.WHITE);
}
}
要将 StatusBar 恢复到以前的状态:
public static void clearLightStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Window window = activity.getWindow();
window.setStatusBarColor(ContextCompat
.getColor(activity,R.color.colorPrimaryDark));
}
}
恢复状态栏的颜色就足够了,它还恢复了图标的颜色。 非常重要:在 setLightStatusBar(View view..) 中使用的视图从屏幕上消失(即 view.getVisibility()==GONE|INVISIBLE)之前,不会发生恢复操作。
根据尼克布彻的项目“格子”
public static void clearLightStatusBar(@NonNull View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
}
}
你可以在这里找到这个文件。
我基于@Aracem 和@Carlos Hernández Gil,但我认为如果我们使用按位异或(Java 中的^运算符)会很容易理解
private void setLightStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = activity.getWindow().getDecorView().getSystemUiVisibility(); // get current flag
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // add LIGHT_STATUS_BAR to flag
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.GRAY); // optional
}
}
private void clearLightStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = activity.getWindow().getDecorView().getSystemUiVisibility(); // get current flag
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // use XOR here for remove LIGHT_STATUS_BAR from flags
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.GREEN); // optional
}
}
解释
首先看SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
和setSystemUiVisibility
/**
* Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that
* is compatible with light status bar backgrounds.
*/
public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
public void setSystemUiVisibility(int visibility) {
if (visibility != mSystemUiVisibility) {
mSystemUiVisibility = visibility;
...
}
}
我认为下面的两行代码很难理解
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // for set light status bar
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // for clear light status bar
乍一看,我只是觉得我们可以使用简单的like
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // for set light status bar
flags = 0; // for clear light status bar (0 <=> LIGHT_STATUS_BAR <=> default systemUiVisibility)
但我们应该使用|
和^
因为
例如,我们想将状态栏和导航栏都设置为亮,那么我们将使用
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
当我们不想让状态栏变亮时,我们可以使用
flags = View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
或者
flags = activity.getWindow().getDecorView().getSystemUiVisibility();
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
了解更多我们为什么使用|
和^
,我认为下面的教程可能会有所帮助https://medium.com/@JakobUlbrich/flag-attributes-in-android-how-to-use-them-ac4ec8aee7d1这是我的理解。 希望这有帮助
我为 API 23-30 切换明暗的方式与这些有点不同。 这是一个科特林版本
由于我使用 Compose 和 Crossfade 动画来更改主题,因此在某些情况下会调用此函数两次,从而使xor
自行撤消。 另一种方法是逆or
运算。 我的灯光主题切换器最终看起来像这样
@Suppress("DEPRECATION")
fun invertInsets(darkTheme: Boolean, window: Window) {
if (Build.VERSION.SDK_INT >= 30) {
//Correct way of doing things
val statusBar = APPEARANCE_LIGHT_STATUS_BARS
val navBar = APPEARANCE_LIGHT_NAVIGATION_BARS
if (!darkTheme) {
window.insetsController?.setSystemBarsAppearance(statusBar, statusBar)
window.insetsController?.setSystemBarsAppearance(navBar, navBar)
} else {
window.insetsController?.setSystemBarsAppearance(0, statusBar)
window.insetsController?.setSystemBarsAppearance(0, navBar)
}
} else {
// Does bitwise operations (or to add, inverse or to remove)
// This is depreciated but the new version is API 30+ so I should have this here
val flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
if (Build.VERSION.SDK_INT >= 26) View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR else 0
if (!darkTheme) {
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or flags
} else {
window.decorView.systemUiVisibility =
(window.decorView.systemUiVisibility.inv() or flags).inv()
}
}
}
API 30+ 的位没有贬值,但实际上 API 30 的手机并不多,因此也有较低 API 的位
它只是为了简洁而预先计算标志(因为设置LIGHT_NAVIGATION_BARS
是 API 26+),然后明确设置或重置这些确切的标志。 不and
或xor
或有趣的生意。 or
将始终将标志设置为1
,反之 or 将始终将标志设置为0
。 这是唯一可能的,因为SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
和SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
都是一位。 否则它可能需要使用xor
。
我将这个简单的实用程序对象放在一起,它允许您在任何片段中更改状态栏颜色和亮状态栏的开/关。 但是,这依赖于使用 Android Jetpack Navigation 组件进行导航 (Kotlin):
object StatusBarUtil {
fun changeStatusBarColor(activity: Activity, @ColorInt color: Int, lightStatusBar: Boolean) {
activity.window?.let { win ->
val nav = Navigation.findNavController(activity, R.id.your_nav_host_fragmen /* TODO: Use the ID of your nav host fragment */)
val currentDest = nav.currentDestination?.id
val oldColor = win.statusBarColor
val oldFlags = win.decorView.systemUiVisibility
win.statusBarColor = color
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
var flags = oldFlags
flags = if (lightStatusBar) {
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
win.decorView.systemUiVisibility = flags
}
nav.addOnNavigatedListener { _, dest ->
if (dest.id != currentDest) {
win.statusBarColor = oldColor
win.decorView.systemUiVisibility = oldFlags
}
}
}
}
}
要使用它,请从任何片段的onViewCreated
中调用以下命令:
StatusBarUtil.changeStatusBarColor(requireActivity(), someDarkColor, false)
SDK 的 API 30 略有变化,现在灯光状态栏的外观由WindowInsetsController控制,可以从Window获得。 下面是 Kotlin 中的示例方法(在 Activity 中),将新 API 与之前用于旧 Android SDK 版本的View.setSystemUiVisibility结合起来。 请记住,这只会改变状态栏的系统图标外观,状态栏的实际颜色仍然可以通过Window.setStatusBarColor设置。
@Suppress("DEPRECATION")
private fun setSystemUiLightStatusBar(isLightStatusBar: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val systemUiAppearance = if (isLightStatusBar) {
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
} else {
0
}
window.insetsController?.setSystemBarsAppearance(systemUiAppearance,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS)
} else {
val systemUiVisibilityFlags = if (isLightStatusBar) {
window.decorView.systemUiVisibility or SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
window.decorView.systemUiVisibility and SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
window.decorView.systemUiVisibility = systemUiVisibilityFlags
}
}
}
systemUiVisibility
- 现在已弃用。 您可以改用WindowInsetsControllerCompat
。
private val insetsController: WindowInsetsControllerCompat? by lazy {
activity?.window?.let { window -> WindowInsetsControllerCompat(window, window.decorView) }
}
private fun setLightStatusBar(light: Boolean) {
insetsController?.isAppearanceLightStatusBars = light
}
UPD : WindowInsetsControllerCompat
的上述构造函数已弃用,因此请改用以下实例化:
private val insetsController: WindowInsetsControllerCompat? by lazy {
activity?.window?.decorView?.let(ViewCompat::getWindowInsetsController)
}
基于@phan-van-linh 的回答,我为 Xamarin Android 编写了这个类
public static class ActivityExtensions
{
public static void SetLightStatusBar(this Activity activity)
{
int flags = (int)activity.Window.DecorView.SystemUiVisibility; // get current flag
flags |= (int)SystemUiFlags.LightStatusBar; // add LIGHT_STATUS_BAR to flag
activity.Window.DecorView.SystemUiVisibility = (StatusBarVisibility)flags;
//activity.Window.SetStatusBarColor(Color.GRAY); // optional
}
public static void ClearLightStatusBar(this Activity activity)
{
int flags = (int)activity.Window.DecorView.SystemUiVisibility; // get current flag
flags = flags ^ (int)SystemUiFlags.LightStatusBar; // use XOR here for remove LIGHT_STATUS_BAR from flags
activity.Window.DecorView.SystemUiVisibility = (StatusBarVisibility)flags;
//activity.Window.setStatusBarColor(Color.GREEN); // optional
}
}
要更改为轻状态栏,请使用:-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
要改回深色状态栏:-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
activity?.window?.decorView?.systemUiVisibility = 0
我将对上述答案进行一些更改。
上课
public class DarkStatusBar {
public static void setLightStatusBar(View view, Activity activity){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.WHITE);
}
}
}
并像这样在任何你想要的地方调用它
Window window = getWindow();
View view = window.getDecorView();
DarkStatusBar.setLightStatusBar(view,this);
设置带有浅色文本颜色的蓝色背景状态栏kotlin
版本
fun setBlueStatusBarColor(window: Window, context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
window.statusBarColor = context.getColor(R.color.colorBlue)
}else {
window.statusBarColor = context.resources.getColor(R.color.colorBlue)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
var flags: Int = window.decorView.systemUiVisibility
flags = flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
window.decorView.systemUiVisibility = flags
}
}
}
/**
* Changes color of the status bar icons
* @param isLight if true - shows dark icons, light else
*/
fun setStatusBarUiTheme(activity: Activity?, isLight: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity?.window?.decorView?.let {
it.systemUiVisibility = if (isLight)
it.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR // dark icons
else
it.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() // light icons
}
}
}
在 res/styles.xml
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
.......
</style>
<style name="AppTheme.DarkStatus" parent="AppTheme" tools:targetApi="23" >
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor" >@color/status_bar_color</item>
</style>
在代码中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme_DarkStatus); //To set DarkStatusBar theme
setContentView(R.layout.activity_drawer);
....
}
这个对我有用
fun Activity.clearLightStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val window = window
window.statusBarColor = ContextCompat
.getColor(this, R.color.ultramarine_blue)
}
}
对于没有Window
实例的人。 也可以使用View
实例(对于 API 30):
fun setLightStatusBar(view: View) = view.windowInsetsController?.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)
fun clearLightStatusBar(view: View) = view.windowInsetsController?.setSystemBarsAppearance(
0,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.