美文网首页
【Android】6.0 状态栏及其图标颜色修改(含MIUI、F

【Android】6.0 状态栏及其图标颜色修改(含MIUI、F

作者: HakkaHuang | 来源:发表于2018-04-19 16:15 被阅读0次

    注:虽然原生系统从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

    相关文章

      网友评论

          本文标题:【Android】6.0 状态栏及其图标颜色修改(含MIUI、F

          本文链接:https://www.haomeiwen.com/subject/cauwkftx.html