邮箱:Jack120612@163.com


今天公司的项目忽然要做沉浸式,但是项目都已经很庞大了,没有办法一个一个页面去改,但是又要实现这种效果,怎么办?

这种时候,产品只有一句话,能不能实现!

硬性条件,放弃4.4以下手机的适配(所谓沉浸式状态栏,在4.4以后才开始支持的),api所导致的,这个真的没有办法.
关于基础的只是我这里就不做介绍了

基础知识

献上郭大神的讲解
讲解的很细致,很适合没有接触过得人来学

下面说一下我的做法

  • xml文件的修改
    在API19以上的版本,我在style.xml文件里面进行了简单的设置
<style name="AppTheme" parent="AppBaseTheme">
        <!-- 这个NoTitle可有可无  --!>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowTranslucentStatus">true</item>
</style>

由于我们在整个app应用了这个主题,所以在这个里面在全局就可以生效

  • 代码的修改
    前提是我们的项目有统一的基类进行管理BaseActivity
    下面我们在onCreate方法里面进行设置,一定要保证在setContentView()之前让代码执行.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT&&!(this instanceof StartActivity||this instanceof WelcomeActivity)) {
            ViewGroup firstView = (ViewGroup) ((ViewGroup) getWindow().getDecorView()).getChildAt(0);
            View statusView = new View(this);
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusHeight());
            statusView.setBackgroundColor(getStatusBarColor());
            firstView.addView(statusView, 0, params);
        }

拿到状态栏的高度:

private int getStatusHeight() {
        int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resId > 0) {
            return getResources().getDimensionPixelSize(resId);
        }
        return 0;
    }

原理讲解

  1. 我们首先获取到了跟布局,然后自己创建了一个假的状态栏背景,我们可以吧设置颜色的开放给子类,或者我们根据统一的布局进行计算,然后我们就可以做一个假的状态栏了.
  2. 当然有一些界面是图片进行的显示,那么我们就只能一个个去设置了,这个没有办法,但是因为我们的项目比较规范,所以还是比较好改的.

那么问题就来了,我们有一些界面的背景是白色的,那么怎么去改变状态栏的颜色呢?

关于修改状态栏字体颜色

首先对于这个问题我没有找到太好的解决办法,所以就用了网上的办法.然后我说服产品,就适配了小米,魅族,6.0以上的状态栏字体.连接给出

下面是我改造的工具类

public class StatusBarUtils {
    public static final int MIUI = 1;
    public static final int FLYME = 2;
    public static final int ANDROID_M = 3;
    public static final int ANDROID_OTHER = 4;
    public static int setStatusBarColor(boolean darkmode, Activity activity){
        int result = 4;
        //首先对版本进行判断
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (setMIUIStatusBarDarkMode(darkmode,activity)) {
                result = MIUI;
            } else if (setFlymeStatusBarDarkMode(darkmode,activity)) {
                result = FLYME;
            } else if (setAndroidMStatusBarDarMode(darkmode,activity)) {
                result = ANDROID_M;
            }
        }
        return result;
    }
    /**
     * miuiv6以上设置状态栏字体黑色的配置
     *
     * @param darkmode
     * @param activity
     */
    private static boolean setMIUIStatusBarDarkMode(boolean darkmode, Activity activity) {
        Class<? extends Window> clazz = activity.getWindow().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);
            extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * flyme4以上设置状态栏字体黑色的配置
     *
     * @param darkmode
     * @param activity
     */
    private static boolean setFlymeStatusBarDarkMode(boolean darkmode, Activity activity) {
        Window window = activity.getWindow();
        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 (darkmode) {
                    value |= bit;
                } else {
                    value &= ~bit;
                }
                meizuFlags.setInt(lp, value);
                window.setAttributes(lp);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        } else {
            return false;
        }
    }
    /**
     * api23以上设置状态栏字体黑色的配置
     *
     * @param darkmode
     * @param activity
     */
    private static boolean setAndroidMStatusBarDarMode(boolean darkmode, Activity activity) {
        if (Build.VERSION.SDK_INT >= 23) {
            if (darkmode) {
                // 沉浸式
                activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 0x00002000);
                //非沉浸式
//                activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                return true;
            } else {
                //非沉浸式
                activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
            }
        }
        return false;
    }

工具类就这样了,做了部分的简化,miui6,7,8 Android6,7测试没有问题,魅族没测

  • ps:说一下遇到的坑,首先沉浸式状态栏会造成原本应该在输入法之上的弹窗被输入法给遮挡,造成我们之前已经做好的东西出现问题,我们的解决办法是在EditText的跟布局也加上
android:fitsSystemWindows="true"

这个问题先暂时那么解决,等我有更好的办法,再更新.