安卓动态修改系统状态栏背景和文字颜色,以及动态显示或隐藏系统状态栏

关于动态修改系统状态栏背景、字体和图标颜色,以及动态显示或隐藏系统状态栏,一直都是都是许多项目的常规需求。但是,由于不同版本间的兼容性差异,网上的实现方法多种多样。并且,许多方法都会存在这样、那样的不足。使用麻烦不说,一不小心还会产生各种异常,令人得不偿失。

这里,我们希望使用一个统一、简洁的方法,实现一键修改系统状态栏背景和文字颜色。以及动态的控制系统状态栏的显示或隐藏。

知识储备:安卓在5.0之前,并没有提供可以修改系统状态栏背景色的方法,而在6.0之前,也没有提供修改状态栏文字和图标颜色的方法。另外,国内某些厂商,如小米、魅族等修改了官方API,可能导致修改方法无效等。

因此,要想修改系统状态栏背景色,我们需要系统在5.0以上,而需要修改状态栏文字和图标颜色,则需要系统在6.0以上。这里建议向上兼容,即只有系统在6.0以上才允许动态修改系统状态栏,否则如果5.0的设备将状态栏北京改为白色,而字体颜色无法修改,默认也是白色。那就无法看见了。好在随着安卓系统的不断更新,目前6.0以上系统的覆盖率已经达到90%以上,所以即使无法做到完全覆盖,我们也可以确保绝大部分的用户体验。

下面是具体方案:

1.设置状态栏的背景颜色

// 设置状态栏底色颜色
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(parseColor);

方法非常简单,这个背景色可以设置为任意颜色值,并且可以在任何时刻修改。需要注意的是API必须是5.0以上才有用哦。

2.设置状态栏文字和图标颜色

文字和图标颜色并不能设置为任意颜色,他只有两种选择:亮色系(文字和图标颜色为黑灰色)和暗色系(文字和图标颜色为白色)

根据我们设置的状态栏背景色,我们需要动态修改文字和图标颜色,以保证它们能被看清。例如,当背景色为白色时,我们采用亮色系,当背景色为黑色时,我们采用暗色系。那么问题来了,我的程序怎么知道这个时候该采用哪种色系呢?如果靠人工判断那也太麻烦了。

别慌,官方为我们提供了一个判断方法:

ColorUtils.calculateLuminance(parseColor)

返回值的取值范围为0.0-1.0 当大于0.5时,我们就可以认为当前颜色为亮色系,需要将文字和图标颜色设置为黑灰色;反之,则将文字和图标颜色设置为白色。设置的方法也非常简单:

window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//亮色系,将文字和图标颜色设置为黑灰色
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);//暗色系,将文字和图标颜色设置为白色

这下就大功告成了吗?别急,上面我们说了国内某些厂商,如小米、魅族等修改了官方API,我们会发现这两个方法在小米和魅族的部分机型上会显示无效果。需要针对性的做出兼容处理。

//小米手机兼容处理,修改系统状态栏文字和图标颜色
Class clazz = window.getClass();
try {
    int darkModeFlag = 0;
    Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
    Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
    darkModeFlag = field.getInt(layoutParams);
    Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
    if (dark) {
        extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
    } else {
        extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体,使用默认白色字体
    }
    result = true;
} catch (Exception e) {

}

//魅族手机兼容处理,修改系统状态栏文字和图标颜色

try {
    WindowManager.LayoutParams lp = window.getAttributes();
    Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
    Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
    darkFlag.setAccessible(true);
    meizuFlags.setAccessible(true);
    int bit = darkFlag.getInt(null);
    int value = meizuFlags.getInt(lp);
    if (dark) {
        value |= bit;
    } else {
        value &= ~bit;
    }
    meizuFlags.setInt(lp, value);
    window.setAttributes(lp);
    result = true;
} catch (Exception e) {

}

这是网上找到的修改方法,亲测好用。

那么,我们的完整动态修改系统状态栏背景和文字颜色方法如下:

/*设置状态栏颜色和文字颜色,小米,魅族需要自定义,比较坑爹*/
public static void setColor(Window window, int parseColor) {
    // 操作系统的api版本大于21,才能改变状态栏的颜色,api版本大于23,才能改变状态栏文字颜色
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        try {
            // 设置状态栏底色颜色
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            window.setStatusBarColor(parseColor);
            // 如果亮色,设置状态栏文字为黑色
            boolean dark = ColorUtils.calculateLuminance(parseColor) >= 0.5;
            if(MIUISetStatusBarLightMode(window,dark)){
                //小米的设置成功
                /*Logger.e("setColor","小米手机,设置成功");*/
            }else if(FlymeSetStatusBarLightMode(window,dark)){
                //魅族的设置成功
                /*Logger.e("setColor","魅族手机,设置成功");*/
            }else{
                if (ColorUtils.calculateLuminance(parseColor) >= 0.5) {
                    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                } else {
                    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * 小米MIUI系统 亲测好用
 *
 * @param window
 * @param dark
 * @return
 */
public static boolean MIUISetStatusBarLightMode(Window window, boolean dark) {
    boolean result = false;
    if (window != null) {
        Class clazz = window.getClass();
        try {
            int darkModeFlag = 0;
            Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
            Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
            darkModeFlag = field.getInt(layoutParams);
            Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
            if (dark) {
                extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
            } else {
                extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
            }
            result = true;
        } catch (Exception e) {

        }
    }
    return result;
}

/**
 * 设置状态栏图标为深色和魅族特定的文字风格
 * 可以用来判断是否为Flyme用户
 *
 * @param window 需要设置的窗口
 * @param dark   是否把状态栏字体及图标颜色设置为深色
 * @return boolean 成功执行返回true
 */
public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
    boolean result = false;
    if (window != null) {
        try {
            WindowManager.LayoutParams lp = window.getAttributes();
            Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
            Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
            darkFlag.setAccessible(true);
            meizuFlags.setAccessible(true);
            int bit = darkFlag.getInt(null);
            int value = meizuFlags.getInt(lp);
            if (dark) {
                value |= bit;
            } else {
                value &= ~bit;
            }
            meizuFlags.setInt(lp, value);
            window.setAttributes(lp);
            result = true;
        } catch (Exception e) {

        }
    }
    return result;
}

建议将以上方法放到你的工具类里,具体界面调用时只需一行代码就可以搞定了。

ToolsUtil.setColor(mContext.getWindow(), Color.WHITE);

至于动态控制系统状态栏的显示或隐藏。也很简单:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN);//隐藏状态栏

动态显示状态栏直接用上面提到的的ToolsUtil.setColor方法,就可以一并实现了。

补充PS:至于网上说的那种沉浸式状态栏,由于需要调整布局,所以使用起来没这么简单,建议如非必要,不要这么做。具体方法给出如下:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);//设置沉浸模式
getWindow().setStatusBarColor(Color.TRANSPARENT);//设置状态栏背景透明
//需要调整布局,为状态栏显示预留出空间

再次补充PS:还有一种随滑动手势实现状态栏颜色渐变的需求,本文没有提到。不过谷歌已经提供了很好的解决方案,CoordinatorLayout,有兴趣的可以自行百度一下。本文不做细讲,我们只说一下,什么时候去修改状态栏里的文字和图标颜色。

我们只需要监听AppBarLayout的onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)方法,根据偏移量verticalOffset的值,动态设定状态栏里的文字和图标颜色即可。

 

 

 

 

 

 

 

    原文作者:mzy24511cs
    原文地址: https://blog.csdn.net/mzy24511cs/article/details/98068322
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞