Android中沉浸式状态栏的学习

之前对于状态栏这块一直处于模糊状态,不是很清楚,实现方式也一直使用的之前很流行的SystemBarTintManager这个类库,后来遇到白底+黑字样式的状态栏,类似首页轮播、我的等一些页面要和状态栏融为一体,简单实现之后,在此记录一下,如果有那些地方不正确,还请指出,在此感谢,注:本文结合网上一些其他博客和资料,本文底部会给出相关参考链接。

**测试手机:魅族pro6s 7.1.1 ; 红米4A 6.0.1 ,三星GalaxyJ3 7.1.1

一:首先我们先实现状态栏和toolbar颜色一致的效果,效果如下:
这里写图片描述
代码如下:

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0及以上
       View decorView = activity.getWindow().getDecorView();
       int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
       decorView.setSystemUiVisibility(option);
       this.getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimary));
  } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.45.0 
       WindowManager.LayoutParams localLayoutParams = activity.getWindow().getAttributes();
       localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
  }
  setStatusTextColor(false,this);

在layout的根布局加上 android:fitsSystemWindows=”true” 即可,使设置的颜色与toolbar或者title布局的背景保持一致就可以了
代码很简单,具体各个Flag的意思,可自行百度,到处都是资料。下面我们来实现类似首页轮播和状态栏融为一体的效果,先看效果:
这里写图片描述
这里提一下,从6.0开始,状态栏文字颜色有深浅色调这么一说,可以设置View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR标记进行修改设置。相关代码如下:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0及以上
         View decorView = activity.getWindow().getDecorView();
         int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
         decorView.setSystemUiVisibility(option);
         activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
         activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
         activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
 }
 setStatusTextColor(false,this);

这样设置之后会出现布局和状态栏重叠的问题,在第一种效果去掉android:fitsSystemWindows属性就会出现该问题,网上有很多解决方法,比如SystemBarTintManager类中就是通过add一个view的方式实现的,或者在布局中给合适的View添加一个padding或者margin,再或者放一个空布局隐藏显示等,fragment中同理,这里我们使用空布局隐藏显示的方法来实现,布局如下:
这里写图片描述
把id为layout_state_bar的View放到头部布局合适的位置,然后把该View的高度设置成状态栏的高度,获取方式有好几种,这里我们采取新建value方式,在value-19中加入:

 <dimen name="status_bar_height">25dp</dimen>

在默认的value中加入:

 <dimen name="status_bar_height">0dp</dimen>

代码如下

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    layout_state_bar.setVisibility(View.VISIBLE);
    //获取到状态栏的高度
    int statusHeight = getStatusBarHeight(this);
    try {
       //动态的设置隐藏布局的高度
        if (layout_state_bar.getParent() instanceof LinearLayout) {
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) layout_state_bar.getLayoutParams();
            params.height = statusHeight;
            layout_state_bar.setLayoutParams(params);
        } else if (layout_state_bar.getParent() instanceof RelativeLayout) {
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) layout_state_bar.getLayoutParams();
            params.height = statusHeight;
            layout_state_bar.setLayoutParams(params);
       } else if (view.getParent() instanceof FrameLayout) {
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) layout_state_bar.getLayoutParams();
            params.height = statusHeight;
            layout_state_bar.setLayoutParams(params);
       }
    } catch (Exception e) {
        e.printStackTrace();
        Toast.makeText(this, "布局类型转换错误", Toast.LENGTH_LONG).show();
    }
 }

注:我这里layout_state_bar的父布局是LinearLayout,使用的时候要注意。
一般我们使列表布局滑动到一定具体会动态改变头部View的alpha和设置相关图标,这个时候,我们可以利用6.0中的SYSTEM_UI_FLAG_LIGHT_STATUS_BAR这个标记来实现,这里给出几个方法,代码如下:

    /**
     * 设置状态栏文字色值为深色调
     *
     * @param useDart  是否使用深色调
     * @param activity
     */
    public static void setStatusTextColor(boolean useDart, Activity activity) {
        if (isFly()) {
            processFlyMe(useDart, activity);
        } else if (isMiUi()) {
            processMIUI(useDart, activity);
        } else {
            if (useDart) {
                setStatusDarkTextColor(activity);
            } else {
                setStatusTintTextColor(activity);
            }
        }
    }


    /**
     * 深色(黑色字体)
     *
     * @param activity
     */
    private static void setStatusDarkTextColor(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //6.0
            activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        }
    }
    /**
     * 浅色(白色字体)
     *
     * @param activity
     */
    private static void setStatusTintTextColor(Activity activity) {
        activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
    }

通过调用setStatusTextColor()方法就可控制状态栏字体的颜色,代码中有一部分为适配小米和魅族的代码。
下面贴出代码:

    /**
     * 要求MiUi6以上  lightStatusBar为true时表示黑色字体,反之白色
     */
    private static void processMIUI(boolean lightStatusBar, Activity activity) {
        Class<? extends Window> clazz = activity.getWindow().getClass();
        try {
            int darkModeFlag;
            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(), lightStatusBar ? darkModeFlag : 0, darkModeFlag);
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }

   /**
     * 要求FlyMe4以上  isLightStatusBar为true时表示黑色字体,反之白色
     */
    private static void processFlyMe(boolean isLightStatusBar, Activity activity) {
        WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
        try {
            Class<?> instance = Class.forName("android.view.WindowManager$LayoutParams");
            int value = instance.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON").getInt(lp);
            Field field = instance.getDeclaredField("meizuFlags");
            field.setAccessible(true);
            int origin = field.getInt(lp);
            if (isLightStatusBar) {
                field.set(lp, origin | value);
            } else {
                field.set(lp, (~value) & origin);
            }
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }

注意,这里有个小米手机的深坑,真是坑,坑的不要不要的,小米开发版 7.7.13 及以后版本采用了系统的API,以上设置会不起作用,所以要修改一下,如下:

/**
     * 要求MiUi6以上  lightStatusBar为true时表示黑色字体,反之白色
     */
    private static void processMIUI(boolean lightStatusBar, Activity activity) {
        Class<? extends Window> clazz = activity.getWindow().getClass();
        try {
            int darkModeFlag;
            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(), lightStatusBar ? darkModeFlag : 0, darkModeFlag);
            //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
            if (lightStatusBar) {
                setStatusDarkTextColor(activity);
            } else {
                setStatusTintTextColor(activity);
            }
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }

以上就是遇到的一些问题和主要实现代码,这里给出一个封装类,方便大家使用,如上述代码有错误之处,还请指出,再次感谢!!

下载地址

参考链接:
白底黑字!Android浅色状态栏黑色字体模式
android标题栏、状态栏图标文字颜色及背景动态变化

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值