关于Android状态栏反色(白底黑字)的适配小总结

我尽量不打错别字,用词准确,不造成阅读障碍。

昨天在OPPO开发者后台清理未读消息时看到一篇介绍状态栏反色(白底黑字)的文章,心血来潮看了一下,然后就查阅了国内各个ROM的不同处理方式,写一篇小总结,希望能帮助到需要的人。

前言

Android6.0(M)以后,Google给出了官方修改状态栏白底黑字的方式 ,各大厂商基本都适用,所以应该不用适配 (“应该”是因为我没有那么多手机,没法逐个确认),在6.0之前的系统,国内不同厂家有的提供了实现方法,有的没有。比如我查阅到的几家,MIUI6开始提供了方法,OPPO的Color3.0开始且Android5.1提供了方法,魅族Flyme4.0提供了方法,华为开发者文档里没查到,vivo开发者文档里没查到,论坛里有说是Android5.0以后才提供沉浸式状态栏设置,其他手机没查了比如三星、索尼什么的(其实是因为没有测试机)。

注意:个人觉得状态栏基本有三个修改点:1.透明,全屏 ;2.改背景颜色与主题适配(感觉和上一个差不多);3.白底黑字或黑底白字;这三个修改点Google给出的官方方法时间不一样,前两个5.0就可以了,如果是4.4,网上也有很多实现的方法和思路,最后一个官方在6.0以后才给出方法,所以项目中写状态栏工具的时候还是要考虑很多东西的。

我手里的测试机有

华为荣耀6P:Android6.0 & EMUI4.0.1;//由于华为手机没有文档,所以还是很有测试价值的

红米R3s:Android6.0 & MIUI9; //MIUI6实在找不到,那得什么年代的机子了?

OPPOR9m:Android5.1 & Color3.0; //6.0以下的只有这一部

小米8:Android8.1.0 & MIUI10.0;

各种模拟器;

虽然设备条件不足,但是还是有一些可取之处的,所以只希望能提供一些帮助。

一.Android6.0及以上

效果四连:

捕获

捕获2

捕获3

捕获4

主要就是改成黑色字体,背景其实好改很多。

代码如下:

public static void setStatusColor(Activity activity, boolean isTranslate, boolean isDarkText, @ColorRes int bgColor) {
    //如果系统为6.0及以上,就可以使用Android自带的方式
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      Window window = activity.getWindow();
      View decorView = window.getDecorView();
      window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); //可有可无
      decorView.setSystemUiVisibility((isTranslate ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN : 0) | (isDarkText ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0));
      window.setStatusBarColor(isTranslate ? Color.TRANSPARENT : ContextCompat.getColor(activity, bgColor)); //Android5.0就可以用
     } 
 }

在setSystemUiVisibility里面设置就可以分别实现全屏和文字黑色;

二.Android6.0以下

MIUI6以上

小米文档写的是MIUI全面支持原生写法,MIUI中Android6.0及以上用原生的,MIUI6以上Android6.0以下用MIUI自己的,所以你得写两套。首先要判断是否是MIUI6以后的版本:

private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";
private static boolean isMIUI6Later() {
   try {
        Class<?> cla = Class.forName("android.os.SystemProperties");
        Method mtd = cla.getMethod("get", String.class);
        String val = (String) mtd.invoke(null, KEY_VERSION_MIUI);
        val = val.replaceAll("[vV]", "");
        int version = Integer.parseInt(val);
        return version >= 6;
   } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

网上还有一种获取厂商自定义系统的方法,具体忘记了,那个方法很耗时,几百毫秒左右,使用反射一般就1~2毫秒。

根据官方文档,设置透明和设置状态栏反色是两个步骤:

//设置透明
private static void setMIUI6Translate(Activity activity, boolean on) {
    Window win = activity.getWindow();
    WindowManager.LayoutParams winParams = win.getAttributes();
    final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
    if (on) {
        winParams.flags |= bits;
    } else {
        winParams.flags &= ~bits;
    }
        win.setAttributes(winParams);
  }

//设置黑色字符
 private static void setMIUI6StatusBarDarkMode(Activity activity, boolean darkmode) {
        Class<? extends Window> clazz = activity.getWindow().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);
            extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

由于我没有MIUI6以上&Android6.0以下的手机,所以没有测试,但是这是官方文档给的方法,应该是有保证的。

链接:https://dev.mi.com/console/doc/detail?pId=1159

官方还给了实现白色字符的方式:

int flag =window.getDecorView().getSystemUiVisibility()&~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
window.getDecorView().setSystemUiVisibility(flag);
OPPOColor3.0

官方只给了Color3.0&Android5.1的情况,其它的也没说不行或行,是不是Color3.0以上Android6.0以下只有这一种机器?先判断系统是不是Color3.0以上的,与判断MIUI6的方法一样:

private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";
private static boolean isColorOS_3() {
        try {
            Class<?> cla = Class.forName("android.os.SystemProperties");
            Method mtd = cla.getMethod("get", String.class);
            String val = (String) mtd.invoke(null, KEY_VERSION_OPPO);
            val = val.replaceAll("[vV]", "");
            val = val.substring(0, 1);
            int version = Integer.parseInt(val);
            return version >= 3;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

设置字体颜色:

private void setOppoStausBar(){
    //控制字体颜色,只有黑白两色
    int SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT = isDarkText ? 0x00000010 : 0x00190000;
    Window window = activity.getWindow();
    View decorView = window.getDecorView();
    decorView.setSystemUiVisibility((isTranslate ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN : 0) | SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT);
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); //可有可无
    window.setStatusBarColor(isTranslate ? Color.TRANSPARENT : ContextCompat.getColor(activity, bgColor));
}

可以看出来,OPPO的修改与Android6.0以上的修改唯一不同的就是setSystemUiVisibility中设置字符颜色的标识是自己手写的,不是使用系统的,官方给的是0x00000010,这个数值我随便输了几个,发现只有黑白两色。
开发者链接:https://open.oppomobile.com/wiki/doc#id=10161

Flyme4.0

魅族我没有机子,都是在官方的基础上归纳的:判断是否为Flyme4.0:

private static boolean isFlyme4Later() {
    if ("MEIZU".equals(Build.BRAND.trim().toUpperCase())) {
           return Build.FINGERPRINT.contains("Flyme_OS_4") || Build.VERSION.INCREMENTAL.contains("Flyme_OS_4") || Pattern.compile("Flyme_OS_[4|5]", Pattern.CASE_INSENSITIVE)
                    .matcher(Build.DISPLAY).find();
     }
     return false;
}

郑重说明,我没有机子,这个方法是网上找的,我本来一位可以使用判断小米和OPPO一样的方法,但是不行,没找到KEY_VERSION,没有机子也测不了。

设置字体颜色:

 private static void darModeForFlyme4(Activity activity, boolean dark) {
        boolean result = false;
        try {
            WindowManager.LayoutParams e = activity.getWindow().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(e);
            if (dark) {
                value |= bit;
            } else {
                value &= ~bit;
            }
            meizuFlags.setInt(e, value);
            activity.getWindow().setAttributes(e);
        } catch (Exception var8) {
            Log.e("StatusBar", "darkIcon: failed");
        }
    }

以上是个整合版本,官方给了一个工具类,链接:http://open-wiki.flyme.cn/doc-wiki/index#id?79

吐槽一句,魅族真麻烦,周围连个测试机都没有。

其他

包括没找到文档的华为、VIVO,没找文档的三星、索尼、诺基亚、锤子、360等

设置全屏透明及背景色:

public static void setStatusTranslate(Activity activity) {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
       View decorView = activity.getWindow().getDecorView();
       decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
       activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
   } else {
     //感觉5.0以下(4.4及以下)可以放弃了
       activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
   }
}

public static void setStatusBarColor(Activity activity, int color) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            activity.getWindow().setStatusBarColor(activity.getResources().getColor(color));
    }
}

因为没有文档,所以没有找到设置状态栏反色的方法,如果是Android6.0及以上,以上品牌应该是都可以使用原生方法的。

本文旨在提供一些帮助,因为测试机有限,所以可能帮助的不多,你也可以再次基础上进行添加等修改,以符合项目要求。完整代码如下:

public class StatusBarUtil {
    private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";    //OPPO
    private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";     //小米
    private static final String KEY_VERSION_EMUI = "ro.build.version.emui";       //华为
    private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";   //锤子
    private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";          //vivo

    /**
     * 设置状态栏透明度、背景颜色、文字颜色
     * @param isTranslate 是否透明,若为true,则bgColor设置无效
     * @param isDarkText  字体颜色,只有黑白两色,无论什么色值,都只会转为黑白两色
     * @param bgColor     背景色,即状态栏颜色,isTranslate若为true则此值无效
     */
    public static void setStatusColor(Activity activity, boolean isTranslate, boolean isDarkText, @ColorRes int bgColor) {
        //如果系统为6.0及以上,就可以使用Google自带的方式
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Window window = activity.getWindow();
            View decorView = window.getDecorView();
            //可有可无
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);   
            decorView.setSystemUiVisibility((isTranslate ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN : 0) | (isDarkText ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0));
            window.setStatusBarColor(isTranslate ? Color.TRANSPARENT : ContextCompat.getColor(activity, bgColor));
        } else { //如果不是6.0及以上则分情况适配
            if (isColorOS_3()) { //如果是OPPO Color3.0 & Android 5.1
                //控制字体颜色,只有黑白两色
                final int SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT = isDarkText ? 0x00000010 : 0x00190000;  
                Window window = activity.getWindow();
                View decorView = window.getDecorView();
                decorView.setSystemUiVisibility((isTranslate ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN : 0) | SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT);
                //可有可无
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
                window.setStatusBarColor(isTranslate ? Color.TRANSPARENT : ContextCompat.getColor(activity, bgColor));
            } else if (isMIUI6Later()) { //如果是Android 6.0以下,MIUI6及以上
                setMIUI6Translate(activity, isTranslate);
                setMIUI6StatusBarDarkMode(activity, isDarkText);
            } else if (isFlyme4Later()) {
                darModeForFlyme4(activity, isDarkText);
                if (isTranslate) {
                    setStatusTranslate(activity);
                }
            } else {
     //既不属于MIUI6,也不属于OPPO,还不属于魅族,极有可能是华为、三星、索尼、诺基亚、VIVO、锤子、360等
                if (isTranslate) {
                    setStatusTranslate(activity);
                }
                setStatusBarColor(activity, isTranslate ? Color.TRANSPARENT : ContextCompat.getColor(activity, bgColor));
            }
        }
    }

    /**
     * 是否是MIUI6及以后版本
     * @return 是否是MIUI6
     */
    private static boolean isMIUI6Later() {
        try {
            Class<?> cla = Class.forName("android.os.SystemProperties");
            Method mtd = cla.getMethod("get", String.class);
            String val = (String) mtd.invoke(null, KEY_VERSION_MIUI);
            val = val.replaceAll("[vV]", "");
            int version = Integer.parseInt(val);
            return version >= 6;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 设置MIUI6及以上状态栏透明,字体为默认白色,Android6.0以上也可以
     * @param on 是否为透明
     */
    private static void setMIUI6Translate(Activity activity, boolean on) {
        Window win = activity.getWindow();
        WindowManager.LayoutParams winParams = win.getAttributes();
        final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        if (on) {
            winParams.flags |= bits;
        } else {
            winParams.flags &= ~bits;
        }
        win.setAttributes(winParams);
    }

    /**
     * 设置MIUI6及以上,Android6.0以下版本状态栏黑色字符
     * Android 6.0以上此方法无效
     * 此方法是官方给的,应该没有错,我没有MIUI6的手机,无法测试
     */
    private static void setMIUI6StatusBarDarkMode(Activity activity, boolean darkmode) {
        Class<? extends Window> clazz = activity.getWindow().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);
            extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 是否是ColorOS_3.0系统 Android 5.1
     * @return 是否是colorOS_3.0
     */
    private static boolean isColorOS_3() {
        try {
            Class<?> cla = Class.forName("android.os.SystemProperties");
            Method mtd = cla.getMethod("get", String.class);
            String val = (String) mtd.invoke(null, KEY_VERSION_OPPO);
            val = val.replaceAll("[vV]", "");
            val = val.substring(0, 1);
            int version = Integer.parseInt(val);
            return version >= 3;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判断是否是魅族Flyme4
     * @return 是否是魅族Flyme4
     */
    private static boolean isFlyme4Later() {
        if ("MEIZU".equals(Build.BRAND.trim().toUpperCase())) {
            return Build.FINGERPRINT.contains("Flyme_OS_4") || Build.VERSION.INCREMENTAL.contains("Flyme_OS_4") || Pattern.compile("Flyme_OS_[4|5]", Pattern.CASE_INSENSITIVE)
                    .matcher(Build.DISPLAY).find();
        }
        return false;
    }

    /**
     * 设置魅族Flyme4以后 状态栏黑色字体
     * 没有手机,从网上找的方法,应该没问题
     * @param dark 是否黑色
     */
    private static void darModeForFlyme4(Activity activity, boolean dark) {
        boolean result = false;
        try {
            WindowManager.LayoutParams e = activity.getWindow().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(e);
            if (dark) {
                value |= bit;
            } else {
                value &= ~bit;
            }
            meizuFlags.setInt(e, value);
            activity.getWindow().setAttributes(e);
        } catch (Exception var8) {
            Log.e("StatusBar", "darkIcon: failed");
        }
    }

    /**
     * 设置状态栏透明,Android4.4、Android5.0以上方法不一
     * 我感觉5.0以下的系统已经很少了吧,应该不需要适配了吧
     * 如果只是设置状态栏透明,就使用这个就好了
     */
    public static void setStatusTranslate(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            View decorView = activity.getWindow().getDecorView();
            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
        } else {
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
    }

    /**
     * 设置状态栏背景颜色,不适配5.0以下系统
     * @param color 颜色值
     */
    public static void setStatusBarColor(Activity activity, int color) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            activity.getWindow().setStatusBarColor(activity.getResources().getColor(color));
        }
    }
}

你可能感兴趣的:(Android日常开发知识点)