Android最简单实现沉浸式状态栏

经过这些年的摸爬滚打,总算在最新的项目中实现了真正的沉浸式,也许有人比我更早,但是我不管你,我只管我(明学家)!
我写这个博客的目的就是让大家复制过去,直接调用就实现,当然该明白的也得明白。

转载注明出处,CSDN第三篇

又转眼到了11月下旬,这个项目也优化的差不多了,可能有些小页面没有发现,咱也不细追了。只是在首页呀随着轮播图改变状态栏颜色的这个功能做的真不错,只是没有完美的沉浸,因为状态栏明显比轮播图背景多了一层灰色,嘿嘿,你看碰到我了。。。

沉浸式的适配历史

沉浸式最早是在android4.4上出现,但是5.0之后又做了修改,所以我们一般做判断的分界线就是4.4和5.0,我这边貌似只适配到4.4,因为实在找不到4.4以下的手机去测试啦!

众所周知,现在都是9012年的尾巴了,网上各种沉浸式状态栏的文章是多如牛毛,我曾经也各种复制各种实验,奈何无果,所以不是所有的文章都那么良心的啦,当然我也没啥良心。

沉浸式的适配效果描述

首先沉浸式要设置没有标题栏的主题,这样方便自己控制颜色。

<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
style>

目前代码可以分为两部分,一部分是针对状态栏高度的,这个用不用看个人喜好。另一部分是修改状态栏颜色的。
话说了很多,上代码:

第一部分 针对状态栏高度:

1、第一种方式(推荐)根布局添加属性

  <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:fitsSystemWindows="true"
    android:clipToPadding="true"
    android:orientation="vertical">
</LinearLayout>

根布局添加android:fitsSystemWindows=“true”,如果设置为true会在你的根布局上加入状态栏高度的空白,设置为false你的根布局就会紧贴屏幕顶部,和时间什么的重叠。

2、第二种方式(习惯)根布局添加控件

若是不想用上面的办法,可以在根布局加入一个view,然后动态设置他的高度,好处也是获取到这个view可以随便的改颜色,例如首页四个fragment中有点要显示状态栏,有的不显示状态,切换一下又要换颜色等等

  <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical">
    	<View
            android:id="@+id/statuTop"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
</LinearLayout>

可以在activity中用下面的方法动态改变它的高度。

   /**
     * 反射获取任务栏高度设置给view
     * @param statuTop
     */
    public void setStatuTop(View statuTop) {
        if (statuTop != null) {
            int size = getResources().getDimensionPixelSize(getResources().getIdentifier("status_bar_height", "dimen", "android"));
            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) statuTop.getLayoutParams();
            //用margin或padding的话状态栏颜色不好控制
//            layoutParams.topMargin = size;
//            statuTop.setPadding(0, size, 0, 0);
            layoutParams.height = size;
            statuTop.setLayoutParams(layoutParams);
        }
    }

第二部分 针对状态栏颜色和字体颜色:

我的一系列代码都写在BaseActivity里面,不像别人还弄个util,我是那种连util都懒得调的人,何况这个状态栏只在activity中用呢。
话不多说,先上代码:

   /**
     * 设置任务栏字体颜色
     * @param isDark 这里的是否黑色,如果是黑色背景传true字体就会白色,不是传false字体黑色
     */
    protected void setStatuDark(boolean isDark) {
        setStatuDark(Color.TRANSPARENT, isDark);
    }
     /**
     * 设置任务栏颜色和字体颜色
     * @param color  可以自定义颜色
     * @param isDark 这里的是否黑色,如果是黑色背景传true字体就会白色,不是传false字体黑色
     */
    protected void setStatuDark(int color, boolean isDark) {
        if (MIUISetStatusBarLightMode(this, isDark)) {
        } else if (FlymeSetStatusBarLightMode(getWindow(), isDark)) {
        } else {
            if (isDark) {
                getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            } else {
                getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
//                activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
            }
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //解决Android5.0以上,状态栏设置颜色后变灰的问题
                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                getWindow().setStatusBarColor(color);
            } else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }
        }
    }

 /**
     * 适配小米沉浸式
     * @param activity
     * @param dark
     * @return
     */
    protected boolean MIUISetStatusBarLightMode(Activity activity, boolean dark) {
        boolean isMIUI = false;
        Window window = activity.getWindow();
        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);//清除黑色字体
                }
                isMIUI = true;

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
                    if (dark) {
                        activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                    } else {
                        activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
                    }
                }
            } catch (Exception e) {

            }
        }
        return isMIUI;
    }

/**
     * 适配魅族沉浸式
     *
     * @param window
     * @param dark
     * @return
     */
    protected boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
        boolean isFlyme = 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);
                isFlyme = true;
            } catch (Exception e) {

            }
        }
        return isFlyme;
    }

调用的时候这么写。

  public class TestActivity extends BaseActivity {
     @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_test);
          //setStatuTop(statuTop);
          setStatuDark(true);
       }
  }

沉浸式状态栏适配结尾

就这么简单就实现了,其实还可以扩展,根据当前状态栏颜色自动调整字体颜色

  	/**
     * 设置任务栏颜色,根据颜色明亮自动调整状态栏字体颜色
     * @param color
     */
    protected void setStatuColor(int color) {
        setStatuDark(ColorUtils.calculateLuminance(color) >= 0.5);
    }

另外提一嘴,ColorUtilsArgbEvaluator真是好用。。。处理一切颜色

你可能感兴趣的:(Android)