零、摘要
Android全屏透明状态栏的文章已经有不少了,也有开源的库甚至,本文着重讲具体实施背后遇到的那些坑。
一、为什么
现有很多app在Android机器上状态栏的体验并不好,有一道灰色的条。比如手机QQ在7.0 vivo上的效果:
![](https://img.haomeiwen.com/i6634880/7a3ff0a2e6a58e0f.jpg)
我们期望的效果是:
- 全屏,app界面的布局延伸到状态栏
- 没有顶部的阴影
- 状态栏背景色为透明或者跟随app界面颜色
-
状态栏字体和icon颜色可以根据界面颜色深浅设置为浅或深,以避免都为浅色或深色而看不见状态栏字体和icon。
如下图所示效果:
图1.2
图中左边状态栏背景是透明,字体是浅色,右边状态栏背景是白色,字体是深色。
二、怎么做
为了达到一中所说的1,2,3和4的效果,先看下Android在api上的支持。
2.1 Android4.4
可以实现状态栏背景色透明或其它颜色,但是做不到效果中的4。
实现步骤:
- 通过配置values-19文件夹下的style属性
<item name="android:windowTranslucentStatus">true</item>
或者activity里设置
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
状态栏透明后,可以再自己定义一个状态栏高度的view,设置其颜色就相当于设置状态栏背景色了。可以参考其它状态栏的文章,不再赘述。
这样得到的效果:
图2.1
然而,试了几款机器,发现并不是所有机型都能达到这个效果,比如vivo的机器上就不行,没有全屏:
![](https://img.haomeiwen.com/i6634880/460e6336992a83ca.jpg)
看效果是全屏的flag没起作用,因为官方文档说,设置了WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS flag后,会自动设置另外两个属性:
When this flag is enabled for a window, it automatically sets the system UI visibility flags SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.
手动把这两个属性设置后,布局倒是延伸到状态栏了,不过状态栏也不见直接隐藏了,有兴趣的可以研究下vivo的4.4机器上能不能做到。
再比如三星机器上,系统会默认给系统状态栏加点阴影:
![](https://img.haomeiwen.com/i6634880/73ad976730b3fa6a.jpg)
再比如oppo r7的coloros 2.1系统上能达到理想效果,也有oppo r7效果不行,状态栏是黑色,可能和coloros的版本有关系吧。
注:如果在android高版本设置了4.4的这个属性,通常会是开篇说的手q那种效果。
2.2 Android5.0和Android5.1
可以直接实现状态栏背景颜色,不用像4.4上需要自己去搞自定义view,当然也可以给状态栏设置一个透明颜色,然后继续用自定义view的方案也是没问题的。但是和4.4一样,没法改变状态栏字体和icon颜色。
按照官方文档:
Sets the color of the status bar to color. For this to take effect, the window must be drawing the system bar backgrounds with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS and FLAG_TRANSLUCENT_STATUS must not be set.
If color is not opaque, consider setting SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.
代码如下:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));
如果不是不透明,也就是有透明度的,把这两个也设置上:
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
具体效果和机型适配不再测试。。。
2.3 Android6.0及以上
到了这里,终于可以完全实现我们要的效果了。因为Api23增加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,可以设置状态栏字体和icon是深颜色还是浅颜色。设置状态栏背景色的api还是和Android5.0上一样。代码差不多就这样:
if(Build.VERSION.SDK_INT >= LOLLIPOP) {
int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(Color.TRANSPARENT);
if(Build.VERSION.SDK_INT >= M) {
uiFlags = setStatusBarDarkFont(uiFlags);
}
getWindow().getDecorView().setSystemUiVisibility(uiFlags);
}
private int setStatusBarDarkFont(int uiFlags) {
if (isSystemSetDarkFontSupport() && mFontDarkMode) {
return uiFlags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
return uiFlags;
}
}
这样设置后我们的app界面就从状态栏顶部开始布局了,根据需要有些界面可以直接在状态栏的位置就显示,有些可能需要从状态栏下沿才开始显示,具体效果可参见图1.2中的左和右,针对后者,我们还可以像4.4一样,自己搞一个假的view占位,也可以用其它不少的方法,具体可参见这篇文章:
http://www.jianshu.com/p/2a884e211a62
本文建议还是自己搞一个假的view占位,原因后面会说。
这样就万事大吉了?如果是的话那就不叫Android了,接下来说说那些坑吧,主要针对Android6.0及以上的系统。
三、坑
3.1 闪的问题
通过2.3中的api设置后,发现很多机器在切换activity时,状态栏会闪一下,解决方案,需要在Activity的style属性里添加:
<item name="android:windowIsTranslucent">true</item>
可以在values-v23文件夹下加。不过加了这个会有些影响:
- 对activity生命周期的影响,Activity A上启动了一个加上此属性的Activity B,A不会走onStop,当B销毁时,A不会走onStart。如果基类Activity或某些Activity在onStart里有些特殊逻辑处理需要注意下。
- 对transition动画可能会有影响,比如我遇到的是通过ActivityOptionsCompat.makeSceneTransitionAnimation做动画的界面,在onBackPressed activity时会黑屏一下,我是在onBackPressed直接finish掉不做动画,不调super.onBackPressed。
3.2 DialogFragment问题
全屏DialogFragment时,发现状态栏顶部还是和开篇说的QQ那样的效果,代码里怎么调都还是那结果,差点放弃。。最后发现,在布局里调用就好了,原因就懒得去找了。
<item name="android:windowTranslucentStatus">false</item>
<item name="android:statusBarColor">@color/thirtyalphablack</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
再特别提一句,meizu flyme上不要通过这种方式,否则状态栏和布局之间会有一条灰线,不过魅族不加这些参数全屏DialogFragment也显示正常。
3.3 左右滑动问题
2.3中说到,尽量自己搞个占位的view来让需要的界面从状态栏下面开始展示,这样一方面是好控制,另一方面是遇到,如果是通过setStatusBarColor或者设置ContentView的padding来的话,左右滑动时,状态栏不会跟着走,这样的效果:
![](https://img.haomeiwen.com/i6634880/242de7e23b61d698.jpg)
这个问题如果不通过占位方式的话,感觉应该也可以解决,有兴趣的可以研究下。
3.4 特例品牌魅族
魅族从FlymeOS4就开始提供了设置状态字体深色或浅色的api了,这里建议判断下是否大于等于Flyme OS4,是的话使用其自己的api,使用系统的反而有问题,好像会导致切换字体颜色时闪。
3.5 特例品牌小米
小米也一样,很早就搞了自己的私有API来设置状态栏字体颜色深浅,不过在其开发版7.7.13后又恢复到原生api了,私有API没有了效果。但是miui的开发版和发布版并没有明确的对应关系,所以系统的和小米的都得调,不过根据MIUI9的发布日志,可以推测MIUI9以后都是开发版7.7.13之后了,所以可以判断下如果是大于等于miui6小于miui9之间,两种api都调,大于等于miui9的话则只需调用系统的。参考链接:
http://www.miui.com/thread-8946673-1-1.html
摘要:
大家好,在本周开发版公测后,MIUI 对状态栏字符颜色的逻辑做了一次调整:
1. 在 Android 6.0 以前,Android 没有方法可以实现「状态栏黑色字符」效果,因此 MIUI 自己做了一个接口;
2. 在 Android 6.0 及以上版本,Android 提供了标准的方法实现「状态栏黑色字符」效果,但这个方法和 MIUI 的方法产生了冲突,
所以当开发者使用 Android 标准方法时,没有出现预期的效果,这给很多开发者都造成了困扰,尤其是海外开发者。
基于以上背景,我们决定兼容 Android 的方法,舍弃 MIUI 的自己的实现方法。这个改动将会在 7.7.13 公测开发版开始生效(内测版本已生效),
之后随稳定版外发。非常抱歉给各位带来麻烦,但长远来看,兼容 Android 的标准,减少了开发者的适配成本,对整个 Android 生态也更为有利。
http://www.miui.com/thread-8944996-1-1.html
摘要
MIUI 9 第一个内测版本已于7月27日上午10:00进行推送。首批适配机型:小米手机6、红米Note 4X-高通版(其他机型将分批陆续进行内测)。
已申请 MIUI 9 内测报名并通过审核的米粉,请注意阅读以下升级方式:
1. 小米手机6:7.7.20开发版/体验版米粉,可通过 OTA 更新增量包方式,升级至 MIUI 9。
2. 红米Note 4X-高通版:7.7.13开发版、7.7.22体验版,可通过 OTA 更新增量包方式,升级至 MIUI 9。
3.6 全屏切换问题
切换到全屏时,如果隐藏状态栏了,那么这种情况下就不要调用上述函数。
四、总结
- 上述实现可以放基类Activity的onResume里,然后添加些可以被子类重写的函数,比如状态栏字体颜色深浅,界面展示是可以和状态栏重合还是得从状态栏下沿开始等。
- Android真是坑,API好难用!
五、感谢
最感谢的是这篇文章及其代码了:
http://www.jianshu.com/p/2a884e211a62
网友评论