简体   繁体   English

Android M Light and Dark status bar programmatically - 如何让它再次变暗?

[英]Android M Light and Dark status bar programmatically - how to make it dark again?

In the Android M we have ability to make status bar icons dark.在 Android M 中,我们可以使状态栏图标变暗。 To do that we can specify attribute in the theme's xml:为此,我们可以在主题的 xml 中指定属性:

<item name="android:windowLightStatusBar">true</item>

OR we cat set it at runtime with this code:或者我们在运行时用这段代码设置它:

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

And it actually works fine.它实际上工作正常。 But question is how to properly set a status bar mode to dark at runtime?但问题是如何在运行时正确地将状态栏模式设置为暗?

I already tried these variants:我已经尝试过这些变体:

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

So how it can be done the right way?那么如何以正确的方式完成呢?

The solution posted by @Aracem is valid but, doesn't work if you try change also the background color of the status bar. @Aracem 发布的解决方案是有效的,但是如果您尝试更改状态栏的背景颜色,则不起作用。 In my case I do it in the following way.就我而言,我按以下方式进行操作。

To enable windowLightStatusBar(programatically,inside a Utils class for example):要启用 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); 
            }
}

To restore to StatusBar to the previous state:要将 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)); 
        }
    }

Restoring the color of the status bar is enough, it restores also the icons colors.恢复状态栏的颜色就足够了,它还恢复了图标的颜色。 VERY IMPORTANT: The restore operation will not occur until the view used in setLightStatusBar(View view..) dissapears(that is, view.getVisibility()==GONE|INVISIBLE) from the screen.非常重要:在 setLightStatusBar(View view..) 中使用的视图从屏幕上消失(即 view.getVisibility()==GONE|INVISIBLE)之前,不会发生恢复操作。

According to Nick Butcher's project "Plaid"根据尼克布彻的项目“格子”

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

You can find this file here .你可以在这里找到这个文件。

I base on @Aracem and @Carlos Hernández Gil but I think it will easy to understand if we use bitwise XOR ( ^ operator in Java)我基于@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
    }
}

Explain解释

First, look at SYSTEM_UI_FLAG_LIGHT_STATUS_BAR and setSystemUiVisibility首先看SYSTEM_UI_FLAG_LIGHT_STATUS_BARsetSystemUiVisibility

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

I think 2 lines code below is quite hard to understand我认为下面的两行代码很难理解

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

At first look, I just think we can use simple like乍一看,我只是觉得我们可以使用简单的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)

But we should use |但我们应该使用| and ^ because^因为
Example, we want to set both status bar and navigationbar to light, then we will use例如,我们想将状态栏和导航栏都设置为亮,那么我们将使用

flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);

When we don't want status bar is light anymore, we can use当我们不想让状态栏变亮时,我们可以使用

flags = View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);

OR或者

flags = activity.getWindow().getDecorView().getSystemUiVisibility();
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 
activity.getWindow().getDecorView().setSystemUiVisibility(flags);

To know more why we use |了解更多我们为什么使用| and ^ , I think the tutorial below may help https://medium.com/@JakobUlbrich/flag-attributes-in-android-how-to-use-them-ac4ec8aee7d1 Here is my understand.^ ,我认为下面的教程可能会有所帮助https://medium.com/@JakobUlbrich/flag-attributes-in-android-how-to-use-them-ac4ec8aee7d1这是我的理解。 Hope this help希望这有帮助

The way I switched light and dark for APIs 23-30 was a little different than these.我为 API 23-30 切换明暗的方式与这些有点不同。 This is a kotlin version这是一个科特林版本

Since I was using Compose with the Crossfade animation to change themes, in some cases would call this function twice, hence making xor undo itself.由于我使用 Compose 和 Crossfade 动画来更改主题,因此在某些情况下会调用此函数两次,从而使xor自行撤消。 An alternative is an inverse or operation.另一种方法是逆or运算。 My light theme switcher-thing ended up looking like this我的灯光主题切换器最终看起来像这样

@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()
        }
    }
}

The bit for API 30+ is what's not depreciated, but realistically not many phones are at API 30 so there's also the bit for lower APIs API 30+ 的位没有贬值,但实际上 API 30 的手机并不多,因此也有较低 API 的位

It just calculates flags (since setting LIGHT_NAVIGATION_BARS is API 26+) beforehand for conciseness and then either definitively sets or resets those exact flags.它只是为了简洁而预先计算标志(因为设置LIGHT_NAVIGATION_BARS是 API 26+),然后明确设置或重置这些确切的标志。 No and or xor funny buisiness.andxor或有趣的生意。 or will always set the flags to 1 , and the inverse or thing will always set the flags to 0 . or将始终将标志设置为1 ,反之 or 将始终将标志设置为0 This is only possible because both SYSTEM_UI_FLAG_LIGHT_STATUS_BAR and SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR are one bit, however.这是唯一可能的,因为SYSTEM_UI_FLAG_LIGHT_STATUS_BARSYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR都是一位。 Otherwise it would probably need to use xor .否则它可能需要使用xor

I put together this simple utility object that allows you to change status bar color and light status bar on/off for within any fragment.我将这个简单的实用程序对象放在一起,它允许您在任何片段中更改状态栏颜色和亮状态栏的开/关。 However, this relies on using the Android Jetpack Navigation component for navigation (Kotlin):但是,这依赖于使用 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
                }
            }
        }
    }
}

To use this, call the following from within any fragment's onViewCreated :要使用它,请从任何片段的onViewCreated中调用以下命令:

StatusBarUtil.changeStatusBarColor(requireActivity(), someDarkColor, false)

There is a slight change in API 30 of the SDK and now the light status bar appearance is controlled by WindowInsetsController , which can be obtained from a Window . SDK 的 API 30 略有变化,现在灯光状态栏的外观由WindowInsetsController控制,可以从Window获得。 Below is a sample method (within an Activity) in Kotlin, combining the new API with the previously used View.setSystemUiVisibility for older Android SDK versions.下面是 Kotlin 中的示例方法(在 Activity 中),将新 API 与之前用于旧 Android SDK 版本的View.setSystemUiVisibility结合起来。 Bear in mind that this only changes the system icons appearance of the status bar and the actual color of the status bar can still be set by Window.setStatusBarColor .请记住,这只会改变状态栏的系统图标外观,状态栏的实际颜色仍然可以通过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 - is deprecated now. systemUiVisibility - 现在已弃用。 You can use WindowInsetsControllerCompat instead.您可以改用WindowInsetsControllerCompat

private val insetsController: WindowInsetsControllerCompat? by lazy {
    activity?.window?.let { window -> WindowInsetsControllerCompat(window, window.decorView) }
}

private fun setLightStatusBar(light: Boolean) {
    insetsController?.isAppearanceLightStatusBars = light
}

UPD : Above constructor for WindowInsetsControllerCompat is deprecated, so use the following instantiation instead: UPDWindowInsetsControllerCompat的上述构造函数已弃用,因此请改用以下实例化:

private val insetsController: WindowInsetsControllerCompat? by lazy {
    activity?.window?.decorView?.let(ViewCompat::getWindowInsetsController)
}

Based on @phan-van-linh answer, I wrote this class for Xamarin Android基于@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
    }
}

To change to light status bar use:-要更改为轻状态栏,请使用:-

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
     activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

To change back to dark status bar :-要改回深色状态栏:-

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
     activity?.window?.decorView?.systemUiVisibility = 0

i will make some changes in above answers.我将对上述答案进行一些更改。

make a class上课

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

and Call it wherever you want like this并像这样在任何你想要的地方调用它

        Window window = getWindow();
        View view = window.getDecorView();
        DarkStatusBar.setLightStatusBar(view,this);

Set blue background status bar with light text color kotlin version设置带有浅色文本颜色的蓝色背景状态栏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
        }
    }
}

In res/styles.xml在 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>

In code在代码中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setTheme(R.style.AppTheme_DarkStatus);  //To set DarkStatusBar theme
    setContentView(R.layout.activity_drawer);
    ....
}

It works for me这个对我有用

fun Activity.clearLightStatusBar() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val window = window
        window.statusBarColor = ContextCompat
            .getColor(this, R.color.ultramarine_blue)
    }
}

For people who doesn't have a Window instance.对于没有Window实例的人。 It's also possible to do with a View instance (For API 30):也可以使用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.

相关问题 深色状态栏中的浅色文本在 Android 11 中不起作用 - Light text in dark status bar is not working in Android 11 基于图像的亮/暗状态栏 - Light/dark Status Bar based on image behind 如何在Android上的Dark App Bar上使用Light SearchView? - How can I use Light SearchView on Dark App Bar on android? Android 浅色/深色主题操作栏文字 - Android light/dark theme action bar text android-如何使动画线成一圈亮或暗 - android-How to make an animation lines in a circle light or dark 如何使用 Kotlin 使状态栏以深色文本颜色完全透明 - How to make the status bar completely transparent with dark text color with Kotlin 在深色和浅色通知状态栏图标之间切换 - Change between dark and light notification status bar icons 即使使用 Holo Light 主题,Honeycomb 状态栏仍然保持黑暗 - Honeycomb Status Bar remains dark even with Holo Light theme React Native CLI - 如何正确管理底部Android导航栏颜色? 浅色模式下的白色/深色模式下的深色? - React Native CLI - How to properly manage the bottom Android navigation bar color? White in light mode / Dark in dark mode? 如何在Flutter中使Android状态栏亮起 - How to make Android status bar light in Flutter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM