美文网首页Android研究院Android实用技术MD风格
Android实现修改状态栏背景.字体.图标颜色

Android实现修改状态栏背景.字体.图标颜色

作者: Jlanglang | 来源:发表于2017-09-19 21:24 被阅读647次

    转载请标明出处:http://www.jianshu.com/p/73a117136105
    本文出自:Jlanglang

    前言:

    Android开发,对于状态栏的修改,实在是不友好,没什么api可以用,
    不像ios那么方便.但是ui又喜欢只搞ios一套.
    没办法.各种翻源码,写反射.真的蛋疼.

    需求场景:

    当toolbar及状态栏需要为白色或浅色时(如简书),状态栏由于用的Light风格Theme,字体,图标也都是白色,会看不清.
    如果改变成黑色就很和谐了.

    一.修改状态栏颜色:

    改变状态栏颜色,可以看看这篇文章
    传送门:实现状态栏(statusbar)渐变效果其实很简单

    传送门实现的效果:

    这种方法实现的状态栏变色,没有黑色背景.


    Paste_Image.png

    --------------------------------------分割线----------------------------------------

    使用全屏模式实现的效果如下(QQ的效果):
    Paste_Image.png

    很明显的半透明黑色背景.

    我用的手机是华为,系统7.0

    二.修改状态栏字体:

    通用工具类:

    public class StatusBarUtil {
    
        /**
         * 设置状态栏黑色字体图标,
         * 适配4.4以上版本MIUIV、Flyme和6.0以上版本其他Android
         *
         * @return 1:MIUUI 2:Flyme 3:android6.0
         */
        public static int getStatusBarLightMode(Window window) {
            int result = 0;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                if (MIUISetStatusBarLightMode(window, true)) {
                    result = 1;
                } else if (FlymeSetStatusBarLightMode(window, true)) {
                    result = 2;
                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                    result = 3;
                } else {//5.0
    
                }
            }
            return result;
        }
    
        /**
         * 已知系统类型时,设置状态栏黑色字体图标。
         * 适配4.4以上版本MIUIV、Flyme和6.0以上版本其他Android
         */
        public static void setStatusBarLightMode(Window window) {
            int type = getStatusBarLightMode(window);
            if (type == 1) {
                MIUISetStatusBarLightMode(window, true);
            } else if (type == 2) {
                FlymeSetStatusBarLightMode(window, true);
            } else if (type == 3) {
                window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            } else {//5.0
                
            }
        }
    
       /**
         * 清除MIUI或flyme或6.0以上版本状态栏黑色字体
         */
        public static void StatusBarDarkMode(Window window) {
            int type = getStatusBarLightMode(window);
            if (type == 1) {
                MIUISetStatusBarLightMode(window, false);
            } else if (type == 2) {
                FlymeSetStatusBarLightMode(window, false);
            } else if (type == 3) {
                window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
            }
    
        }
    
        /**
         * 设置状态栏图标为深色和魅族特定的文字风格
         * 可以用来判断是否为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;
        }
    
        /**
         * 设置状态栏字体图标为深色,需要MIUIV6以上
         *
         * @param window 需要设置的窗口
         * @param dark   是否把状态栏字体及图标颜色设置为深色
         * @return boolean 成功执行返回true
         */
        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;
        }
    
    }
    

    activity中使用:

     StatusBarUtil.setStatusBarLightMode(getWindow());
    

    效果:

    Paste_Image.png

    出现的问题:

    1.statusbar背景色变成了colorPrimaryDark默认颜色,
    但是我的配置是白色背景(具体配置代码见最后).

    分析原因:

    setSystemUiVisibility()会刷新view的属性配置.
    由于statusbar默认使用colorPrimaryDark属性.
    所以颜色会变回默认颜色
    
    Paste_Image.png

    此时步骤一设置背景的方法就会失效.

       private void initStatusBar() {
            if (statusBarView == null) {
                int identifier = getResources().getIdentifier("statusBarBackground", "id", "android");
                statusBarView = getWindow().findViewById(identifier);
            }
            if (statusBarView != null) {
                statusBarView.setBackgroundResource(MVPConfig.statusDrawable);
            }
        }
    

    原因:当传入的resid相同时,就不会再次去设置背景色.

    Paste_Image.png

    解决办法:

       private void initStatusBar() {
            if (statusBarView == null) {
                int identifier = getResources().getIdentifier("statusBarBackground", "id", "android");
                statusBarView = getWindow().findViewById(identifier);
            }
            if (statusBarView != null) {
                statusBarView.setBackgroundDrawable(null);//在设置前将背景设置为null;
              //statusBarView.setBackgroundResource(0); //这样也可以 
              statusBarView.setBackgroundResource(MVPConfig.statusDrawable);
            }
        }
    

    修改后的效果:

    Paste_Image.png

    三.完整代码:

    1.MvpConfig

    public class MVPConfig {
        public static int statusDrawable;
        public static int toolbarBackgroundColor;
        public static int toolbarBackgroundDrawable;
        public static int backDrawable;
        public static boolean isStatusBarLight;
    
        public static void setStatusbarDrawable(@DrawableRes int statusDraw) {
            statusDrawable = statusDraw;
        }
    
        public static boolean isStatusBar() {
            return statusDrawable > 0;
        }
    
        public static void setToolbarDrawable(int toolbarBackgroundDrawable) {
            MVPConfig.toolbarBackgroundDrawable = toolbarBackgroundDrawable;
        }
    
        public static void setBackDrawable(int backDrawable) {
            MVPConfig.backDrawable = backDrawable;
        }
    
        public static void setIsStatusBarLight(boolean isStatusBarLight) {
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                MVPConfig.statusDrawable = Color.parseColor("#33ffffff");
            }
            MVPConfig.isStatusBarLight = isStatusBarLight;
        }
    
    
    

    2.Application中

     @Override
        public void onCreate() {
            super.onCreate();
            MVPConfig.setToolbarDrawable(R.color.white);
            MVPConfig.setStatusbarDrawable(R.color.white);
            MVPConfig.setBackDrawable(R.drawable.back);
            MVPConfig.setIsStatusBarLight(true);
    }
    

    3.BaseActivity

       @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
      //延时加载数据.
            Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
                @Override
                public boolean queueIdle() {
                    if (isStatusBarLight()) {
                        StatusBarUtil.setStatusBarLightMode(getWindow());
                    }
                    if (isStatusBar()) {
                        initStatusBar();
                        getWindow().getDecorView().addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                            @Override
                            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                                initStatusBar();
                            }
                        });
                    }
                    mPresenter.initData();
                    return false;
                }
            });
        }
    
     private void initStatusBar() {
            if (statusBarView == null) {
                int identifier = getResources().getIdentifier("statusBarBackground", "id", "android");
                statusBarView = getWindow().findViewById(identifier);
            }
            if (statusBarView != null) {
                if (isStatusBarLight()) {
                    statusBarView.setBackgroundDrawable(null);
                }
                statusBarView.setBackgroundResource(MVPConfig.statusDrawable);
            }
        }
        //子类通过复写该方法,控制是否改变statusbar
        protected boolean isStatusBar() {
            return MVPConfig.isStatusBar();
        }
    //子类通过复写该方法,控制是否需要改变statusbar字体颜色
        protected boolean isStatusBarLight() {
            return MVPConfig.isStatusBarLight;
        }
    
    

    四.补充:

    • 6.0以下,5.0原生系统无法修改字体颜色,用了个比较取巧的办法,设置成半透明灰色.
     public static void setStatusBarLightMode(Window window) {
            int type = getStatusBarLightMode(window);
            if (type == 1) {
                MIUISetStatusBarLightMode(window, true);
            } else if (type == 2) {
                FlymeSetStatusBarLightMode(window, true);
            } else if (type == 3) {
                window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            } else {
                //5.0
                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                    MVPConfig.statusDrawable = Color.parseColor("#33ffffff");
                }
            }
        }
    
    
    • 由于是直接修改window中的statusbarview的背景,而frgament依赖于activity,所以在activity与fragment直接跳转时,状态栏不是很适用.
      比如:
      activity是蓝色,fragment需要是白色,fragment需要通过window修改状态栏颜色.有点麻烦.

    您的喜欢与回复是我最大的动力-_-

    相关文章

      网友评论

      • 卜俊文:最近也在处理状态栏白底黑字的问题,就是5.0的有点麻烦,而且有一款华为的手机,设置透明度会出现各种问题,别的手机都没问题,我就直接给屏蔽了,感觉被坑的好惨。
        Danny_yy:statusBarView是什么啊,可有源码下载地址,看一下
        卜俊文:@Jlanglang HUAWEI p7-L00,EMUI系统3.1的,我是设置了透明度,只能设置透明度了,没办法了。
        Jlanglang::smile: 啥型号的,我觉得5.0的办法就是不设置白底了.至少状态栏不能弄白底,弄个接近的颜色

      本文标题:Android实现修改状态栏背景.字体.图标颜色

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