关于an-d-ro-id:Android关于沉浸式状态栏总结

57次阅读

共计 8962 个字符,预计需要花费 23 分钟才能阅读完成。

一、前言

其实我是不打算写这篇文章的,为什么呢?因为对于沉迷式状态栏的文章太多了,轻易 google 一下就能进去几十上百篇文章,当然这其中有写的好的,也有冒名顶替的。后面在公众号推出了 Material Design 的系列文章,就有读者留言,心愿出一篇对于沉迷式的文章。因而这篇文章就整顿总结一下各个版本的实现原理,顺便为大家举荐一个我感觉很不便的一个库。

二、沉迷式的个别套路

在介绍这个不便的轮子之前,咱们先一起来回顾一下实现沉迷式状态栏的个别套路。在 Android 上,对于对 StatusBar(状态栏)的操作,始终都在一直改善,并且体现越来越好,在 Android4.4 以下,咱们能够对 StatusBar 和 NavigationBar 进行显示和暗藏操作。然而直到 Android4.4, 咱们能力真正意义上的实现沉迷式状态栏。从 Android4.4 到当初(Android 7.1),对于沉迷式大略能够分成三个阶段:

  • Android4.4(API 19)– Android 5.0(API 21): 这个阶段能够实现沉迷式,然而体现得还不是很好,实现形式为: 通过 FLAG_TRANSLUCENT_STATUS 设置状态栏为通明并且为全屏模式,而后通过增加一个与 StatusBar 一样大小的 View,将 View 的 background 设置为咱们想要的色彩,从而来实现沉迷式。
  • Android 5.0(API 21)以上版本: 在 Android 5.0 的时候,退出了一个重要的属性和办法 android:statusBarColor(对应办法为 setStatusBarColor),通过这个办法咱们就能够轻松实现沉迷式。也就是说,从 Android5.0 开始,零碎才真正的反对沉迷式。
  • Android 6.0(API 23)以上版本:其实 Android6.0 以上的实现形式和 Android 5.0 + 是一样,为什么要将它归为一个独自重要的阶段呢?是因为从 Android 6.0(API 23)开始,咱们能够改状态栏的绘制模式,能够显示红色或浅彩色的内容和图标(除了魅族手机,魅族自家有做源码更改,6.0 以下就能实现)

大略就是这个三个阶段,那么接下来咱们就看一下这个三个阶段别离是如何来实现的。

2.1 Android4.4(API 19)– Android 5.0(API 21)实现沉迷式的形式

Android 4.4 为什么可能实现沉迷式的成果呢?因为在 Android 4.4 新增了一个重要的属性:FLAG_TRANSLUCENT_STATUS

 /**
         * Window flag: request a translucent status bar with minimal system-provided
         * background protection.
         *
         * <p>This flag can be controlled in your theme through the
         * {@link android.R.attr#windowTranslucentStatus} attribute; this attribute
         * is automatically set for you in the standard translucent decor themes
         * such as
         * {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor},
         * {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor},
         * {@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and
         * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.</p>
         *
         * <p>When this flag is enabled for a window, it automatically sets
         * the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
         * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.</p>
         */
        public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;

解释:设置状态栏通明,并且变为全屏模式。下面的解释曾经说得很分明了,当 window 的这个属性无效的时候,会主动设置 system ui visibility 的标记 SYSTEM_UI_FLAG_LAYOUT_STABLESYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

有两种形式实现这个属性:

能够在代码中设置,如下:

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

当然也能够在 theme 中设置属性windowTranslucentStatus, 如下:

android:windowTranslucentStatus

成果如下:

成果如上图,能够看出,沉迷式的成果是进去了,然而也有一个问题,咱们的标题栏和状态栏重叠了,相当于整个布局上移了 StatusBar 的高度。

为了让标题栏回到原来的地位,咱们在标题栏的上方增加一个大小和 StatusBar 大小一样的 View,View 的 BackgroundColor 为标题栏一样的色彩,这个 View 起到一个占位的作用。这个时候,标题栏就会下移 StatusBar 的高度,回到失常的地位。

增加如下代码:

       // 获取 windowphone 下的 decorView
        ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        int       count     = decorView.getChildCount();
        // 判断是否曾经增加了 statusBarView
        if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
        } else {
            // 新建一个和状态栏高宽的 view
            StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
            decorView.addView(statusView);
        }
        ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
        //rootview 不会为状态栏留出状态栏空间
        ViewCompat.setFitsSystemWindows(rootView,true);
        rootView.setClipToPadding(true);

创立和 status bar 一样大小的 View 的代码如下:

 private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) {
        // 绘制一个和状态栏一样高的矩形
        StatusBarView statusBarView = new StatusBarView(activity);
        LinearLayout.LayoutParams params =
                new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
        statusBarView.setLayoutParams(params);
        statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
        return statusBarView;
    }

其中 StatusBarView 就是一个一般的 View。

增加上述代码后,成果如下:

通过以上就能够实现 Android 4.4 上的沉迷式状态栏。

另外,如果是一张图片延长到状态栏的话,间接设置 FLAG_TRANSLUCENT_STATUS 就能够了,如下:

小结:Android4.4 上实现沉迷式状态栏的套路是:为 window 增加 FLAG_TRANSLUCENT_STATUS Flag, 而后增加一个和 status bar 一样大小的 View 站位,从而让让标题栏不会与 status bar 重叠。而图片延长到状态栏只须要设置FLAG_TRANSLUCENT_STATUS 就 OK。

后面说过,沉迷式在 Android4.4 – Android5.0 之间的版本体现得不是很好,从下面贴的几张图就能够看出,状态栏的顶部有一个突变,会显示出彩色的暗影(底部的导航栏也是一样的成果),在 Android 5.0 版本曾经被修复了。

2.2 Android 5.0(API 21)以上实现沉迷式的形式

Android 5.0 是一个里程碑式的版本,从 Android 5.0 开始,Google 推出了全新的设计规范 Material Design, 并且原生控件就能够实现一些炫酷的 UI 动效。从这个版本开始,google 退出了一个比拟重要的办法setStatusBarColor (对应属性:android:statusBarColor), 通过这个办法,能够很轻松地实现沉迷式状态栏。办法如下:

 /**
     * Sets the color of the status bar to {@code color}.
     *
     * For this to take effect,
     * the window must be drawing the system bar backgrounds with
     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
     *
     * If {@code color} is not opaque, consider setting
     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
     * <p>
     * The transitionName for the view background will be "android:status:background".
     * </p>
     */
    public abstract void setStatusBarColor(@ColorInt int color);

留神看这个办法的正文,想要这个办法失效,必须还要配合一个 Flag 一起应用,必须设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS , 并且不能设置FLAG_TRANSLUCENT_STATUS(Android 4.4 才用这个)

咱们来看一下 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 这个 flag:

能够看到,这个 flag 也是在 Android 5.0 增加的,它的作用是什么呢?

解释:设置了 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, 表明会 Window 负责零碎 bar 的 background 绘制,绘制通明背景的零碎 bar(状态栏和导航栏),而后用getStatusBarColor()getNavigationBarColor()的色彩填充相应的区域。这就是 Android 5.0 以上实现沉迷式导航栏的原理。

实现沉迷式增加如下代码:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// 留神要革除 FLAG_TRANSLUCENT_STATUS flag
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));

成果如下:

当然也能够间接在 Theme 中应用,在 values-v21 文件夹下增加如下主题:

<style name="MDTheme" parent="Theme.Design.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">false</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/holo_red_light</item>
    </style>

成果和下面代码中增加的成果一样,这里就不贴效果图了。

图片延长到状态栏

在 Android 5.0 使图片延长到状态栏,只需设置windowTranslucentStatus, 将 statusBarColor 设置为通明即可:

<style name="ImageTranslucentTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="android:windowTranslucentStatus">true</item>
        <!-- 设置 statusBarColor 为通明 -->
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>

成果如下:

代码中通过版本号的判断兼容 Android5.0 以下和 Android 5.0 以上:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
            int count = decorView.getChildCount();
            if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
            } else {StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
                decorView.addView(statusView);
            }

            ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
            rootView.setFitsSystemWindows(true);
            rootView.setClipToPadding(true);
            setRootView(activity);
}

2.3 Android 6.0 + 实现状态栏字色和图标浅彩色

应用沉迷式的时候会遇到一个问题,那就是Android 零碎状态栏的字色和图标色彩为红色,当我的主题色或者图片靠近红色或者为浅色的时候,状态栏上的内容就看不清了。,这个问题在 Android 6.0 的时候失去了解决。Android 6.0 新增加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

解释:为 setSystemUiVisibility(int)办法增加的 Flag, 申请 status bar 绘制模式,它能够兼容亮色背景的 status bar。要在设置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDSflag , 同时革除了FLAG_TRANSLUCENT_STATUSflag 才会失效。

增加如下代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}

成果如下:

除了在代码中增加以外,还能够间接在主题中应用属性:

 <style name="MDTheme" parent="Theme.Design.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">false</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/holo_red_light</item>
        <!-- Android 6.0 以上 状态栏字色和图标为浅彩色 -->
        <item name="android:windowLightStatusBar">true</item>
    </style>

留神:主题要放在 values-v23 文件夹下:

三、轮子 StatusBarUtil

通过下面的介绍,其实将各个版本实现沉迷式的形式和原理都讲完了。然而或者当你真正去实际沉迷式状态栏的时候,你会感觉到无从下手,因而,我给大家举荐一个轮子StatusBarUtil

为什么会举荐这个库呢?因为这个库就只有一个类StatusBarUtil, 应用起来很不便,就像一个工具类一样应用。外面封装了很多静态方法,间接应用就好。本人增加也很不便。介绍一下应用的一些场景:

须要在 setContentView() 之后调用:

setContentView(R.layout.main_activity);
...
StatusBarUtil.setColor(MainActivity.this, mColor);
  • 1, 设置状态栏色彩
StatusBarUtil.setColor(Activity activity, int color)

  • 2, 设置状态栏半透明
StatusBarUtil.setTranslucent(Activity activity, int statusBarAlpha)

  • 3, 设置状态栏全透明
StatusBarUtil.setTransparent(Activity activity)

  • 4, 为蕴含 DrawerLayout 的界面设置状态栏色彩(也能够设置半透明和全透明)
StatusBarUtil.setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color)

  • 5, 为应用 ImageView 作为头部的界面设置状态栏通明 ( 罕用的场景为详情页的 Header 局部)
StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView)

  • 6,在 Fragment 中应用

status\_uti

四、最初

以上就是对于沉迷式状态栏的一些总结,心愿能够给还没有应用沉迷式的同学一些帮忙。如果你曾经应用过沉迷式状态栏,也不仿看一下,能够对各个版本实现的原理有一个更深的理解。最初,举荐了一个不错的库,更确切的说,应该是一个不错的工具类。如有问题,欢送交换。

本文转自 https://juejin.cn/post/6844903490402123789,如有侵权,请分割删除。

正文完
 0