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

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


一、修改方案

第一种,设置主题

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

     
    

其中,主要代码:

    @color/white
    true // true:图标为深色;false:图标为浅色
  1. 清单文件引用

     
    
  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 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

你可能感兴趣的:(【Android】6.0 状态栏及其图标颜色修改(含MIUI、Flyme适配) 2018-04-19)