【Android】6.0 状态栏及其图标颜色修改(含MIUI、Flyme适配) 2018-04-19

注:虽然原生系统从4.4开始,就支持状态栏颜色修改,但因原生6.0以下系统不支持状态栏图标颜色的修改,故此处只讨论6.0以上的处理。


一、修改方案

第一种,设置主题

  1. values-23目录下,添加style

     <style name="BaseTheme" parent="Theme.AppCompat.Light">
        <item name="windowActionBar">false</item>
        <item name="android:windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowNoTitle">true</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/white</item>
        <item name="android:statusBarColor">@color/white</item>
        <item name="android:windowLightStatusBar">true</item>
        <item name="android:navigationBarColor">@color/black</item>
        <item name="android:windowBackground">@color/white</item>
        <item name="android:windowAnimationStyle">@style/notAnimation</item>
     </style>
    

其中,主要代码:

    <item name="android:statusBarColor">@color/white</item>
    <item name="android:windowLightStatusBar">true</item> // true:图标为深色;false:图标为浅色
  1. 清单文件引用

     <activity  
           android:name=".activity.MainActivity"
           android:theme="@style/BaseTheme"/>
    
  2. 同样,Dialog也可引用

     AlertDialog.Builder alert = new AlertDialog.Builder(activity, R.style.BaseTheme)
    

第二种,代码动态设置

public void setStatusBarColor(String color, boolean isDark) {
    try {
        int colorInt = Color.parseColor(color);
        setStatusBarColor(colorInt, isDark);
    } catch (Exception e) {
        
    }
}

public void setStatusBarColor(int color, boolean isDark) {
    // set statusbar icon color
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 注:此处实际应区分4.4以上、5.0、6.0以上,进行不同的处理
        String osName = "Other";
        if (MIUISetStatusBarLightMode(this, isDark)) {
            osName = "MIUI";
        } else if (FlymeSetStatusBarLightMode(this, isDark)) {
            osName = "Flyme";
        }
        // 以下为原生6.0设置状态栏深/浅色主题的代码。此处因MIUI在Android 6.0 、开发版 7.7.13 及以后版本已舍弃自家的方案,故这里没有分else,而是调用原生方法再次对状态栏图标颜色进行设置。PS:经测试,Flyme没有此问题。
        int ui = getWindow().getDecorView().getSystemUiVisibility();
        if (isDark) {
            ui |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
        } else {
            ui &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
        }
        getWindow().getDecorView().setSystemUiVisibility(ui);
        getWindow().setStatusBarColor(color);
    }
}

/**
 * MIUI 6.0以上(代码来自MIUI开放平台)
 *
 * @param activity
 * @param isDark
 * @return
 */
public static boolean MIUISetStatusBarLightMode(Activity activity, boolean isDark) {
    return MIUISetStatusBarLightMode(activity.getWindow(), isDark);
}

public static boolean MIUISetStatusBarLightMode(Window window, boolean isDark) {
    try {
        Class<? extends Window> clazz = window.getClass();
        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(window, isDark ? darkModeFlag : 0, darkModeFlag);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

/**
 * Flyme 4.0以上
 *
 * @param activity
 * @param isDark
 * @return
 */
public static boolean FlymeSetStatusBarLightMode(Activity activity, boolean isDark) {
    try {
        FlymeStatusbarColorUtils.setStatusBarDarkIcon(activity, isDark);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

Flyme设置代码(来自Flyme开放平台)

public class FlymeStatusbarColorUtils {
private static Method mSetStatusBarColorIcon;
private static Method mSetStatusBarDarkIcon;
private static Field mStatusBarColorFiled;
private static int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0;

static {
    try {
        mSetStatusBarColorIcon = Activity.class.getMethod("setStatusBarDarkIcon", int.class);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    try {
        mSetStatusBarDarkIcon = Activity.class.getMethod("setStatusBarDarkIcon", boolean.class);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    try {
        mStatusBarColorFiled = WindowManager.LayoutParams.class.getField("statusBarColor");
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
    try {
        Field field = View.class.getField("SYSTEM_UI_FLAG_LIGHT_STATUS_BAR");
        SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = field.getInt(null);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

/**
 * 判断颜色是否偏黑色
 *
 * @param color 颜色
 * @param level 级别
 * @return
 */
public static boolean isBlackColor(int color, int level) {
    int grey = toGrey(color);
    return grey < level;
}

/**
 * 颜色转换成灰度值
 *
 * @param rgb 颜色
 * @return 灰度值
 */
public static int toGrey(int rgb) {
    int blue = rgb & 0x000000FF;
    int green = (rgb & 0x0000FF00) >> 8;
    int red = (rgb & 0x00FF0000) >> 16;
    return (red * 38 + green * 75 + blue * 15) >> 7;
}

/**
 * 设置状态栏字体图标颜色
 *
 * @param activity 当前activity
 * @param color    颜色
 */
public static void setStatusBarDarkIcon(Activity activity, int color) {
    if (mSetStatusBarColorIcon != null) {
        try {
            mSetStatusBarColorIcon.invoke(activity, color);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    } else {
        boolean whiteColor = isBlackColor(color, 50);
        if (mStatusBarColorFiled != null) {
            setStatusBarDarkIcon(activity, whiteColor, whiteColor);
            setStatusBarDarkIcon(activity.getWindow(), color);
        } else {
            setStatusBarDarkIcon(activity, whiteColor);
        }
    }
}

/**
 * 设置状态栏字体图标颜色(只限全屏非activity情况)
 *
 * @param window 当前窗口
 * @param color  颜色
 */
public static void setStatusBarDarkIcon(Window window, int color) {
    try {
        setStatusBarColor(window, color);
        if (Build.VERSION.SDK_INT > 22) {
            setStatusBarDarkIcon(window.getDecorView(), true);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 设置状态栏字体图标颜色
 *
 * @param activity 当前activity
 * @param dark     是否深色 true为深色 false 为白色
 */
public static void setStatusBarDarkIcon(Activity activity, boolean dark) {
    setStatusBarDarkIcon(activity, dark, true);
}

private static boolean changeMeizuFlag(WindowManager.LayoutParams winParams, String flagName, boolean on) {
    try {
        Field f = winParams.getClass().getDeclaredField(flagName);
        f.setAccessible(true);
        int bits = f.getInt(winParams);
        Field f2 = winParams.getClass().getDeclaredField("meizuFlags");
        f2.setAccessible(true);
        int meizuFlags = f2.getInt(winParams);
        int oldFlags = meizuFlags;
        if (on) {
            meizuFlags |= bits;
        } else {
            meizuFlags &= ~bits;
        }
        if (oldFlags != meizuFlags) {
            f2.setInt(winParams, meizuFlags);
            return true;
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    return false;
}

/**
 * 设置状态栏颜色
 *
 * @param view
 * @param dark
 */
private static void setStatusBarDarkIcon(View view, boolean dark) {
    int oldVis = view.getSystemUiVisibility();
    int newVis = oldVis;
    if (dark) {
        newVis |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
    } else {
        newVis &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
    }
    if (newVis != oldVis) {
        view.setSystemUiVisibility(newVis);
    }
}

/**
 * 设置状态栏颜色
 *
 * @param window
 * @param color
 */
private static void setStatusBarColor(Window window, int color) {
    WindowManager.LayoutParams winParams = window.getAttributes();
    if (mStatusBarColorFiled != null) {
        try {
            int oldColor = mStatusBarColorFiled.getInt(winParams);
            if (oldColor != color) {
                mStatusBarColorFiled.set(winParams, color);
                window.setAttributes(winParams);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 设置状态栏字体图标颜色(只限全屏非activity情况)
 *
 * @param window 当前窗口
 * @param dark   是否深色 true为深色 false 为白色
 */
public static void setStatusBarDarkIcon(Window window, boolean dark) {
    if (Build.VERSION.SDK_INT < 23) {
        changeMeizuFlag(window.getAttributes(), "MEIZU_FLAG_DARK_STATUS_BAR_ICON", dark);
    } else {
        View decorView = window.getDecorView();
        if (decorView != null) {
            setStatusBarDarkIcon(decorView, dark);
            setStatusBarColor(window, 0);
        }
    }
}

private static void setStatusBarDarkIcon(Activity activity, boolean dark, boolean flag) {
    if (mSetStatusBarDarkIcon != null) {
        try {
            mSetStatusBarDarkIcon.invoke(activity, dark);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    } else {
        if (flag) {
            setStatusBarDarkIcon(activity.getWindow(), dark);
        }
    }
}}

二、踩坑

在小米设配上,如果Dialog为全屏显示,状态栏颜色会受Dialog主题影响,而非原来Activity设置的颜色。这时需要在创建Dialog的时候重新设置一下,代码如下:

    // set MIUI status bar
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        dialog.getWindow().setStatusBarColor(Color.WHITE);       
        MIUISetStatusBarLightMode(dialog.getWindow(), true);
    }
    dialog.show();

参考

http://www.miui.com/thread-8946673-1-1.html
http://open-wiki.flyme.cn/index.php?title=%E7%8A%B6%E6%80%81%E6%A0%8F%E5%8F%98%E8%89%B2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,350评论 0 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 2017.12.16 六级是真的难,我以为自己很是有点准备的,可还是在看到翻译的时候崩掉了,听到她说吃青椒还有点心...
    然散阅读 173评论 0 0
  • 这个系列都是跟医学有关的小说和访谈录,一共4本书。特别推荐《欲乐园》。 1.《无影灯》(日)渡边淳一 时间:2月1...
    萧某某712阅读 651评论 0 1
  • 上两周,我去深圳书城(罗湖)买书,一楼有很多培训机构像比较大厂的类似山木培训、华尔街、韦博这些,还有无数小型叫不上...
    月野耕在吃草阅读 793评论 0 1