一、前言
其实我是不打算写这篇文章的,为什么呢?因为对于沉迷式状态栏的文章太多了,轻易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_STABLE
和SYSTEM_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 flaggetWindow().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_BACKGROUNDS
flag ,同时革除了FLAG_TRANSLUCENT_STATUS
flag 才会失效。
增加如下代码:
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,如有侵权,请分割删除。