注明下:沉浸栏完美解决方案文章来源于: https://blog.csdn.net/u014418171/article/details/81223681

首先!!!

使用该方法之前,看了别的文章,使用了其他的方法,请先删掉你在别的文章的代码修改, 相信我, 你绝对能以最简单的方式 让你的项目实现沉浸状态栏兼容~ 包括图片沉浸!
以下代码不能出现!!!
全局搜索你的代码里是否有android:fitsSystemWindows , 删掉!, 没错 删掉!!!
检查你的values、values-v19、values-v21等 是否配置了
如下item标签

// values-v19。v19 开始有 android:windowTranslucentStatus 这个属性// values-v21。5.0 以上提供了 setStatusBarColor()  方法设置状态栏颜色。

凡是在style.xml中 有关 windowTranslucentNavigation、windowTranslucentStatus、statusBarColor 统统删掉,全部删掉~

反正使用了别的沉浸栏方法删干净就对了,不然很容易出现互相干扰,各种bug

ok!!那接下来正式进入正题

来看看我的工程大概结构如下

接下来我们准备一下工具类

1.复制一下SystemBarTintManager类到你的工程
https://github.com/jgilfelt/SystemBarTint/blob/master/library/src/com/readystatesoftware/systembartint/SystemBarTintManager.java

2.创建沉浸栏工具类 StatusBarUtil

public class StatusBarUtil {    public final static int TYPE_MIUI = 0;    public final static int TYPE_FLYME = 1;    public final static int TYPE_M = 3;//6.0    @IntDef({TYPE_MIUI,            TYPE_FLYME,            TYPE_M})    @Retention(RetentionPolicy.SOURCE)    @interface ViewType {    }    /**     * 修改状态栏颜色,支持4.4以上版本     *     * @param colorId 颜色     */    public static void setStatusBarColor(Activity activity, int colorId) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            Window window = activity.getWindow();            window.setStatusBarColor(colorId);        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            //使用SystemBarTintManager,需要先将状态栏设置为透明            setTranslucentStatus(activity);            SystemBarTintManager systemBarTintManager = new SystemBarTintManager(activity);            systemBarTintManager.setStatusBarTintEnabled(true);//显示状态栏            systemBarTintManager.setStatusBarTintColor(colorId);//设置状态栏颜色        }    }    /**     * 设置状态栏透明     */    @TargetApi(19)    public static void setTranslucentStatus(Activity activity) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色            Window window = activity.getWindow();            View decorView = window.getDecorView();            //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;            decorView.setSystemUiVisibility(option);            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);            window.setStatusBarColor(Color.TRANSPARENT);            //导航栏颜色也可以正常设置            //window.setNavigationBarColor(Color.TRANSPARENT);        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            Window window = activity.getWindow();            WindowManager.LayoutParams attributes = window.getAttributes();            int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;            attributes.flags |= flagTranslucentStatus;            //int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;            //attributes.flags |= flagTranslucentNavigation;            window.setAttributes(attributes);        }    }    /**     *  代码实现android:fitsSystemWindows     *     * @param activity     */    public static void setRootViewFitsSystemWindows(Activity activity, boolean fitSystemWindows) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            ViewGroup winContent = (ViewGroup) activity.findViewById(android.R.id.content);            if (winContent.getChildCount() > 0) {                ViewGroup rootView = (ViewGroup) winContent.getChildAt(0);                if (rootView != null) {                    rootView.setFitsSystemWindows(fitSystemWindows);                }            }        }    }    /**     * 设置状态栏深色浅色切换     */    public static boolean setStatusBarDarkTheme(Activity activity, boolean dark) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {                setStatusBarFontIconDark(activity, TYPE_M, dark);            } else if (OSUtils.isMiui()) {                setStatusBarFontIconDark(activity, TYPE_MIUI, dark);            } else if (OSUtils.isFlyme()) {                setStatusBarFontIconDark(activity, TYPE_FLYME, dark);            } else {//其他情况                return false;            }            return true;        }        return false;    }    /**     * 设置 状态栏深色浅色切换     */    public static boolean setStatusBarFontIconDark(Activity activity, @ViewType int type,boolean dark) {        switch (type) {            case TYPE_MIUI:                return setMiuiUI(activity, dark);            case TYPE_FLYME:                return setFlymeUI(activity, dark);            case TYPE_M:            default:                return setCommonUI(activity,dark);        }    }    //设置6.0 状态栏深色浅色切换    public static boolean setCommonUI(Activity activity, boolean dark) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            View decorView = activity.getWindow().getDecorView();            if (decorView != null) {                int vis = decorView.getSystemUiVisibility();                if (dark) {                    vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;                } else {                    vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;                }                if (decorView.getSystemUiVisibility() != vis) {                    decorView.setSystemUiVisibility(vis);                }                return true;            }        }        return false;    }    //设置Flyme 状态栏深色浅色切换    public static boolean setFlymeUI(Activity activity, boolean dark) {        try {            Window window = activity.getWindow();            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);            return true;        } catch (Exception e) {            e.printStackTrace();            return false;        }    }    //设置MIUI 状态栏深色浅色切换    public static boolean setMiuiUI(Activity activity, boolean dark) {        try {            Window window = activity.getWindow();            Class<?> clazz = activity.getWindow().getClass();            @SuppressLint("PrivateApi") Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");            Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");            int darkModeFlag = field.getInt(layoutParams);            Method extraFlagField = clazz.getDeclaredMethod("setExtraFlags", int.class, int.class);            extraFlagField.setAccessible(true);            if (dark) {    //状态栏亮色且黑色字体                extraFlagField.invoke(window, darkModeFlag, darkModeFlag);            } else {                extraFlagField.invoke(window, 0, darkModeFlag);            }            return true;        } catch (Exception e) {            e.printStackTrace();            return false;        }    }    //获取状态栏高度    public static int getStatusBarHeight(Context context) {        int result = 0;        int resourceId = context.getResources().getIdentifier(                "status_bar_height", "dimen", "android");        if (resourceId > 0) {            result = context.getResources().getDimensionPixelSize(resourceId);        }        return result;    }}

3.创建沉Rom类型判断的工具类 OSUtils

public class OSUtils {    public static final String ROM_MIUI = "MIUI";    public static final String ROM_EMUI = "EMUI";    public static final String ROM_FLYME = "FLYME";    public static final String ROM_OPPO = "OPPO";    public static final String ROM_SMARTISAN = "SMARTISAN";    public static final String ROM_VIVO = "VIVO";    public static final String ROM_QIKU = "QIKU";    private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";    private static final String KEY_VERSION_EMUI = "ro.build.version.emui";    private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";    private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";    private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";    private static String sName;    private static String sVersion;    public static boolean isEmui() {        return check(ROM_EMUI);    }    public static boolean isMiui() {        return check(ROM_MIUI);    }    public static boolean isVivo() {        return check(ROM_VIVO);    }    public static boolean isOppo() {        return check(ROM_OPPO);    }    public static boolean isFlyme() {        return check(ROM_FLYME);    }    public static boolean is360() {        return check(ROM_QIKU) || check("360");    }    public static boolean isSmartisan() {        return check(ROM_SMARTISAN);    }    public static String getName() {        if (sName == null) {            check("");        }        return sName;    }    public static String getVersion() {        if (sVersion == null) {            check("");        }        return sVersion;    }    public static boolean check(String rom) {        if (sName != null) {            return sName.equals(rom);        }        if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {            sName = ROM_MIUI;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {            sName = ROM_EMUI;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {            sName = ROM_OPPO;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {            sName = ROM_VIVO;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {            sName = ROM_SMARTISAN;        } else {            sVersion = Build.DISPLAY;            if (sVersion.toUpperCase().contains(ROM_FLYME)) {                sName = ROM_FLYME;            } else {                sVersion = Build.UNKNOWN;                sName = Build.MANUFACTURER.toUpperCase();            }        }        return sName.equals(rom);    }    public static String getProp(String name) {        String line = null;        BufferedReader input = null;        try {            Process p = Runtime.getRuntime().exec("getprop " + name);            input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);            line = input.readLine();            input.close();        } catch (IOException ex) {            return null;        } finally {            if (input != null) {                try {                    input.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return line;    }}

4.开始适配

首先在Activity 的setContentView 下一行编写如下代码(一般你可以写到你的BaseActivity里,否则你每个activity都得写一次)

@Overrideprotected void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.xxx);//绑定布局      //这里注意下 因为在评论区发现有网友调用setRootViewFitsSystemWindows 里面 winContent.getChildCount()=0 导致代码无法继续   //是因为你需要在setContentView之后才可以调用 setRootViewFitsSystemWindows       //当FitsSystemWindows设置 true 时,会在屏幕最上方预留出状态栏高度的 padding   StatusBarUtil.setRootViewFitsSystemWindows(this,true);   //设置状态栏透明   StatusBarUtil.setTranslucentStatus(this);   //一般的手机的状态栏文字和图标都是白色的, 可如果你的应用也是纯白色的, 或导致状态栏文字看不清   //所以如果你是这种情况,请使用以下代码, 设置状态使用深色文字图标风格, 否则你可以选择性注释掉这个if内容  if (!StatusBarUtil.setStatusBarDarkTheme(this, true)) {//true状态栏为黑色文字和图标        //如果不支持设置深色风格 为了兼容总不能让状态栏白白的看不清, 于是设置一个状态栏颜色为半透明,        //这样半透明+白=灰, 状态栏的文字能看得清        StatusBarUtil.setStatusBarColor(this,0x55000000);   } }

以下是Fragment的写法,同样也是建议你的BaseFragment里,否则你每个Fragment都得写一次

 @Override    public void onStart() {        super.onStart();        //这里注意下 因为在评论区发现有网友调用setRootViewFitsSystemWindows 里面 winContent.getChildCount()=0 导致代码无法继续        //是因为你需要在setContentView之后才可以调用 setRootViewFitsSystemWindows        //当FitsSystemWindows设置 true 时,会在屏幕最上方预留出状态栏高度的 padding        StatusBarUtil.setRootViewFitsSystemWindows(getActivity(), true);        //设置状态栏透明        StatusBarUtil.setTranslucentStatus(getActivity());        //一般的手机的状态栏文字和图标都是白色的, 可如果你的应用也是纯白色的, 或导致状态栏文字看不清        //所以如果你是这种情况,请使用以下代码, 设置状态使用深色文字图标风格, 否则你可以选择性注释掉这个if内容        if (!StatusBarUtil.setStatusBarDarkTheme(getActivity(), true)) {            //如果不支持设置深色风格 为了兼容总不能让状态栏白白的看不清, 于是设置一个状态栏颜色为半透明,            //这样半透明+白=灰, 状态栏的文字能看得清            StatusBarUtil.setStatusBarColor(getActivity(), 0x55000000);        }    }

上面先这样 由于界面风格很多, 比如同一个app有 的界面是黑色风格的页面, 有的是白色风格的页面,有的是顶部是图片的界面希望沉浸进去 这样更好看, 同时 此时状态栏文字要跟随改变
比如我这个 4个不同的fragment,有一个是白色, 另外两个是顶部是图片的
我是这样切换状态栏文字深浅色的,你们参考下
界面设置状态栏黑色图标

界面设置状态栏白色图标

改变的代码如下

如果就这样草草结束的话肯定不是我的style了,重点来了!

我要把图片也沉浸进去!!!

想要图片沉浸, 必须设置fitsSystemWindows=false, 以去掉padding效果, 然后想办法 把图片上层的 其他View 整体 paddingTop=状态栏高 让其他View向下挪动
setRootViewFitsSystemWindows(this,false);
去掉padding效果后 图片沉浸了! 但内容进入了状态栏里 被遮挡.
那以最方便的方式就是让整个内容布局 往下挪动
自定义一个View ,用来做状态栏高度占位

StatusBarHeightView 代码如下

/** * 作者:东芝 * 功能:状态栏高度View,用于沉浸占位 */public class StatusBarHeightView extends LinearLayout {    private int statusBarHeight;    private int type;    public StatusBarHeightView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init(attrs);    }    public StatusBarHeightView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(attrs);    }    public StatusBarHeightView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr);        init(attrs);    }    private void init(@Nullable AttributeSet attrs) {        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            if(resourceId>0) {                statusBarHeight = getResources().getDimensionPixelSize(resourceId);            }        }else{            //低版本 直接设置0            statusBarHeight = 0;        }        if (attrs != null) {            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.StatusBarHeightView);            type = typedArray.getInt(R.styleable.StatusBarHeightView_use_type, 0);            typedArray.recycle();        }        if (type == 1) {            setPadding(getPaddingLeft(), statusBarHeight, getPaddingRight(), getPaddingBottom());        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        if (type == 0) {            setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),                    statusBarHeight);        } else {            super.onMeasure(widthMeasureSpec, heightMeasureSpec);        }    } }

attrs.xml

                                                

代码很简单, 就是写一个View, 支持paddingTop= 状态栏高度值 的View,
解释下两个类型:
use_height: 设置当前布局高度=状态栏高度值 用于无子View时的占位
use_padding_top: 设置当前顶部padding=状态栏高度值 用于有子View时的占位
适配低于4.4时 占位View的高度为0 所以不可见

使用方法, 用StatusBarHeightView 来包住你要往下移动的内容! 单独留出要沉浸的View不包住,
举例:

                                                                     


效果如下:

End

如果想详细了解请看原创大佬的文章:Android 沉浸式状态栏完美解决方案

更多相关文章

  1. Android(安卓)zygote与进程创建(一)
  2. ubuntu12.04 64bit编译android ics4.0代码出现的/usr/bin/ld.bfd
  3. 【Android开篇】开始 Hello Android
  4. 美团Android(安卓)DEX自动拆包及动态加载简介
  5. Android(安卓)定时任务过程详解
  6. 利用Android两行代码真正杀死你的App
  7. Android(安卓)ProgressBar 进度条
  8. 我的Android(安卓)NDK之旅(三),使用cmake来构建Jni
  9. Android(安卓)ICS关机跟重新启动功能研究

随机推荐

  1. Android项目初始时的文件
  2. 第3章 UI开发的点点滴滴
  3. Android 运行时权限
  4. android 使用AsyncTask代替thread进行网
  5. ROS + Android
  6. Android Bitmap.setDensity(int density)
  7. Android的px、dip、sp的区别
  8. APK文件粗略介绍
  9. android 判断文件是否存在
  10. Android客户端自动更新代码