其实我是不打算写这篇文章的,为何呢?由于关于沉浸式状态栏的文章太多了,随便google一下就能出来几十上百篇文章,固然这其中有写的好的,也有滥竽充数的。前面在公众号推出了Material Design 的系列文章,就有读者留言,但愿出一篇关于沉浸式的文章。所以这篇文章就整理总结一下各个版本的实现原理,顺便为你们推荐一个我以为很方便的一个库。java
在介绍这个方便的轮子以前,咱们先一块儿来回顾一下实现沉浸式状态栏的通常套路。在Android上,关于对StatusBar(状态栏)的操做,一直都在不断改善,而且表现愈来愈好,在Android4.4 如下,咱们能够对StatusBar和 NavigationBar进行显示和隐藏操做。可是直到Android4.4,咱们才能真正意义上的实现沉浸式状态栏。从Android4.4 到如今(Android 7.1),关于沉浸式大概能够分红三个阶段:android
Android4.4(API 19) - Android 5.0(API 21): 这个阶段能够实现沉浸式,可是表现得还不是很好,实现方式为: 经过FLAG_TRANSLUCENT_STATUS
设置状态栏为透明而且为全屏模式,而后经过添加一个与StatusBar 同样大小的View,将View 的 background 设置为咱们想要的颜色,从而来实现沉浸式。git
Android 5.0(API 21)以上版本: 在Android 5.0的时候,加入了一个重要的属性和方法 android:statusBarColor
(对应方法为 setStatusBarColor),经过这个方法咱们就能够轻松实现沉浸式。也就是说,从Android5.0开始,系统才真正的支持沉浸式。github
Android 6.0(API 23)以上版本:其实Android6.0以上的实现方式和Android 5.0 +是同样,为何要将它归为一个单独重要的阶段呢?是由于从Android 6.0(API 23)开始,咱们能够改状态栏的绘制模式,能够显示白色或浅黑色的内容和图标(除了魅族手机,魅族自家有作源码更改,6.0如下就能实现)ide
大概就是这个三个阶段,那么接下来咱们就看一下这个三个阶段分别是如何来实现的。工具
2.1 Android4.4(API 19) - Android 5.0(API 21)实现沉浸式的方式布局
Android 4.4 为何可以实现沉浸式的效果呢?由于在Android 4.4 新增了一个重要的属性:FLAG_TRANSLUCENT_STATUS
ui
/** * 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
。this
有两种方式实现这个属性:google
能够在代码中设置,以下:
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_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,Github:github.com/laobie/Stat…。
为何会推荐这个库呢?由于这个库就只有一个类StatusBarUtil
,使用起来很方便,就像一个工具类同样使用。里面封装了不少静态方法,直接使用就好。本身添加也很方便。介绍一下使用的一些场景:
须要在setContentView()
以后调用:
setContentView(R.layout.main_activity);
...
StatusBarUtil.setColor(MainActivity.this, mColor);复制代码
StatusBarUtil.setColor(Activity activity, int color)复制代码
StatusBarUtil.setTranslucent(Activity activity, int statusBarAlpha)复制代码
StatusBarUtil.setTransparent(Activity activity)复制代码
StatusBarUtil.setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color)复制代码
StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView)复制代码
以上就是对于沉浸式状态栏的一些总结,但愿能够给尚未使用沉浸式的同窗一些帮助。若是你已经使用过沉浸式状态栏,也不仿看一下,能够对各个版本实现的原理有一个更深的了解。最后,推荐了一个不错的库,更确切的说,应该是一个不错的工具类。若有问题,欢迎交流。
更多Android干货文章,关注公众号【Android技术杂货铺】