共计 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_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 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
通过下面的介绍,其实将各个版本实现沉迷式的形式和原理都讲完了。然而或者当你真正去实际沉迷式状态栏的时候,你会感觉到无从下手,因而,我给大家举荐一个轮子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,如有侵权,请分割删除。