总有一条蜿蜒在童话镇里梦幻的河 分隔了理想分隔现实
又在前方的山口汇合 川流不息扬起水花
又卷入一帘时光入水 让所有很久很久以前 都走到幸福结局的时刻又陌生
程序员的生活不止有代码,其实还有音乐~~~
前言
Androd4.4.4之后我们可以改变状态栏,去掉黑色的状态栏,使用户可以专注于App的界面。 “沉浸式状态栏”和 “透明状态栏”,“沉浸式”是目前国内最普遍的叫法,但是其本质并不是沉浸式,有兴趣的小伙伴可以自行去研究,这里我们姑且叫它 “沉浸式状态栏” 吧~
“沉浸式”状态栏 和 “透明”状态栏并不是一个概念
沉浸式状态栏是整个屏幕只有App的界面,状态栏是浮在上面的,无论它是否透明。
透明状态栏是App的界面在状态栏的下面,但是状态栏是透明
下面是你需要了解的一些常识。
版本 | API | 代号 | 备注 |
---|---|---|---|
Android 4.4.4 | 19 | KITKAT | (MIUI 6 和 FlyMe 4 属于该版本) |
Android 5.0 | 21 | Lollipop | 棒棒糖 |
Android 6.0 | 23 | M | 。。 |
//获得当前手机的Android系统版本
Build.VERSION.SDK_INT
//获得Android系统各个版本
Build.VERSION_CODES.KITKAT
Build.VERSION_CODES.LOLLIPOP
Build.VERSION_CODES.M
三个阶段
1. Android 4.4.4 ~ Andoird 5.0阶段
Android4.4.4之后我们终于可以对状态做手脚了,嘿嘿~
可以通过FLAG_TRANSLUCENT_STATUS
这个flag实现沉浸式代码如下:
WindowManager.LayoutParams winParams = window.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (transparentStatusBar) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
window.setAttributes(winParams);
它实现的效果是一条从上到下的半透明渐变层,App界面占据整个屏幕
不同系统可能略有不同,后面在详述
2. Android 5.0 ~ Android 6.0
Android 5.0 之后我们可以对状态栏进行着色,通过设置flag代码如下:
int flag = window.getDecorView().getSystemUiVisibility();
flag |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
window.setStatusBarColor(statusBarColor)
window.getDecorView().setSystemUiVisibility(flag);
相比第一阶段,我们在Api21实现沉浸式状态栏的同时,可以自定义状态栏的颜色了
如果要实现透明效果只需要让 statusBarColor = Color.TRANSPARENT
Tip:
在Android 5.0 之后我们除了可以在代码中改变状态栏的颜色,还可以在XML中设置主题色,这种方式我们的App不属于沉浸式,在状态栏的下面
2. Android 6.0以后
Api 23之后我们除了可以实现第一阶段和第二阶段的特性外,还可以改变状态栏图标颜色为黑色,这个效果对于沉浸式背景色为白色的页面是很有用的,状态的图标不至于看不清楚了,代码如下:
int flag = window.getDecorView().getSystemUiVisibility();
flag |=(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
window.setStatusBarColor(Color.TRANSPARENT);
window.getDecorView().setSystemUiVisibility(flag);
总结
通过上面对三个阶段的分析,在Api 19 我们可以实现沉浸式, 在Api 21我们可以对状态栏进行着色,在Api 23之后我们可以对改变状态栏的颜色为黑色。有个规律可以方便我们记忆,每个阶段都比上一个阶段增加一个特性,我们对状态栏的可操作性越来越强了。
这里有一点需要提一下,阶段三的特性虽然在Android 6.0 之后才提供,
但是在MIUI 6 和 FlyMe 4 中就可以实现了,而且你用阶段三的
代码去实现亮Icon在小米和魅族手机中是没有效果的,所以在开发中我们需要单独去处理这两个系统,
贴一下处理代码:
/**
* 改变小米的状态栏字体颜色为黑色, 要求MIUI6以上
*/
private void processMIUI(boolean lightStatusBar) throws Exception {
Class extends Window> clazz = window.getClass();
int darkModeFlag;
Class> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(window, lightStatusBar ? darkModeFlag : 0, darkModeFlag);
}
/**
* 改变魅族的状态栏字体为黑色,要求FlyMe4以上
*/
private void processFlyMe(boolean isLightStatusBar) throws Exception {
WindowManager.LayoutParams lp = window.getAttributes();
Class> instance = Class.forName("android.view.WindowManager$LayoutParams");
int value = instance.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON").getInt(lp);
Field field = instance.getDeclaredField("meizuFlags");
field.setAccessible(true);
int origin = field.getInt(lp);
if (isLightStatusBar) {
field.set(lp, origin | value);
} else {
field.set(lp, (~value) & origin);
}
}
使用情景分析
在上文中我们分析了三个阶段的Api特性,那在我们项目中,我们为什么会用到沉浸式呢?在什么情况下会用到沉浸式呢?我总结了一下几点,同时结合我的demo给大家进行演示,请大家结合我的代码来看 「戳这里」
- 改变状态栏颜色,使其与App主题色一致
- 随页面颜色改变状态栏颜色,并且改变状态栏图标icon的颜色
以上的使用情况是可以结合使用的,下面我来分析下正确的使用姿势,我们只考虑Android4.4.4之后的系统,之前的我们是改变不了的
(1)第一种,也是我们在开发中首先要设置的就是在xml中设置各种主题色,这样我们解决了5.0以上的全屏效果,然后我们要单独处理4.4.4 ~5.0 之间的Android系统,需要实现沉浸式,我们可以有两种解决方案,方式A:动态改变Title的paddingTop为状态栏的高度
//详细代码请查看github上demo这里就不贴了
tvTitle = (TextView) findViewById(R.id.tv_title);
AsaSystemBar.from(this)
//版本低于5.0时执行
.setUseBelow(Build.VERSION_CODES.LOLLIPOP)
.setTransparentStatusBar(true)
.setActionbarView(tvTitle)
.setActionbarPadding(true)
.process();
方式B:添加一个View在状态栏的下面,通过设置View的颜色改变状态栏的颜色
但是这种方式,因为实现了沉浸,所以App界面占全屏,设置完View,Title被View挡住了,我们需要在xml中设置根布局的这个属性android:fitsSystemWindows="true"
至此这样我们解决了最基本的4.4.4~5.0的沉浸式全屏,5.0以上的假沉浸式全屏
(2)接下来我们分析第二种使用情况,先看效果吧
我们可以看到随页面变化状态栏图标变黑了,在白色的页面看的很清楚,再来一张Android5.0上的效果图
上图的效果与Android4.4.4的效果一样就不贴图了
之前我们分析过只有在Android 6.0上才能改变状态栏图标的颜色,我们看到5.0上图标还是白色,如果背景是白色的,状态栏的图标就看清了,造成了很不好的用户体验,如果设计师给你这一需求你该怎么处理呢???全部加一个半透明的背景??
我们大概的思路是,针对不同的系统分别处理,6.0以上的系统还是让他变黑,6.0以下的设备就加一个半透明的蒙层。代码如下:
//需要在xml中设置android:fitsSystemWindows="true"
//处理6.0以上的设备
AsaSystemBar.from(SlideViewTintActivity.this)
.setTransparentStatusBar(true)
.setLightStatusBar(true)
.process();
//处理6.0以下的设备
AsaSystemBar.from(SlideViewTintActivity.this)
.setUseBelow(Build.VERSION_CODES.M) //6.0以下使用
.setTransparentStatusBar(true)
.setStatusBarColor(ContextCompat.getColor(SlideViewTintActivity.this, R.color.alpha_50))
.process();
Android 6.0的效果图上面已经贴过了
来看下6.0以下的(注:一直到Android4.4.4效果一致)
>
代码如下:
//添加view + padding的方式
//6.0以上依旧不做处理
AsaSystemBar.from(SlideViewTintActivity.this)
.setTransparentStatusBar(true)
.setLightStatusBar(true)
.setActionbarView(llFoo)
.setActionbarPadding(true)
.process();
//6.0以下的处理
AsaSystemBar.from(SlideViewTintActivity.this)
.setUseBelow(Build.VERSION_CODES.M)
.setTransparentStatusBar(true)
.setActionbarView(llFoo)
.addStatusBarView(true)
.setStatusBarColor(ContextCompat.getColor(SlideViewTintActivity.this, R.color.alpha))
.setActionbarPadding(true)
.process();
细心的同学可能会发现,文字还是被状态栏挡住了,没有实现沉浸式,这里仅仅能对有固定标题的页面有效,因为下面的内容不会滚到标题栏上面去,包括6.0以上也是会被遮挡,因为我们用了android:fitsSystemWindows="true"
好接下来我们来实现不被遮挡的,完全沉浸,而且标题栏icon还是能看清的,以下讨论的依旧是6.0以下的
给布局设置android:fitsSystemWindows="true"
还是有他的局限性的,不能全屏。
那么我们换另一种思路,给title设置padding 并且在xml中父布局设置 android:clipToPadding="true"
不知道的小伙伴自行查资料~~~
这样我们的文字就可以滚动到状态栏下面啦,沉浸式搞定~
看下效果图(4.4.4上效果一致)
注意
我们设置paddingTop一定不要写在xml里,因为我们在代码里是进行了版本判断的,不同版本设置不同,如果你在4.4.4以下的系统安装软件,你会发现,Title上面无端多出来的一块。。。。
除了设置paddingTop我们还可以设置marginTop,但是也一定要做好版本判断。
在4.4.4~5.0Android系统上会有一个渐变的半透明蒙层,白色的Icon也是可以看见的,
但是我们在这里依然为她们增加一个半透明的View的原因是为了兼容MIUI 6 因为在小米上面是透明的
(FlyMe 4上好像也是)至此,心好累。。。。
-。-感觉Android有无尽的坑,好羡慕开发ios的同学·····
占坑
后续会补充
Navigationbar
的处理,再次表示心好累......
结束语
研究沉浸式状态的童鞋,相信通过以上的讲解,对沉浸式状态栏有了相对全面的了解,同时也足以应对大多数沉浸式状态栏的开发需求,那么我花时间写本文的目的也就达到了,表谢,嘿嘿~
上面的核心代码并没有贴出来,请童鞋「戳这里」其中AsaSystembar是本文的核心代码。可以直接拿来使用
研究本文最好是结合代码来研究,边实验边了解
还有为我女神做广告=。=
2016/12/1更新
今天到了魅族的测试机,发现魅族手机状态栏图标没有变暗。。。哪里出了问题,在官网的文档上发现,上面的方法是处理非Activity的情况的,下面贴下处理Activity的代码
if("Meizu".equals(android.os.Build.MANUFACTURER)){
//魅族手机
int oldVis = window.getDecorView().getSystemUiVisibility();
int newVis = oldVis;
if (isLightStatusBar) {
newVis |= 0x00002000;
} else {
newVis &= 0x00002000;
}
if (newVis != oldVis) {
window.getDecorView().setSystemUiVisibility(newVis);
isUsePrivateApi = true;
}
}
路漫漫其修远兮,明天又该上班啦!!!