转自 http://www.jianshu.com/p/c8221fb6b4fc
随着Android版本的迭代,开发者对状态栏等控件有了更多的控制, google 一直在尝试引入新的Api来满足开发者的需求,但Api却一直不够完美,接口添加了很多,却都不够简单或者说完美,算上第三方厂商的特色行为,怎一个“乱”字了得。
当前主流(2017)Android app StatusBar 效果有以下几种:
简单分个类:
与状态栏相关的 Api 主要有以下几个:
// 全屏布局且隐藏状态栏:
//4.4 上,顶部下滑,出现半透明状态栏,过一会儿状态栏消失
//4.1 上,顶部下滑,没反应
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 全屏布局,不隐藏状态栏(可能已失效):
//实测 Support libaray 26.1.0 下(使用 support 库中的主题和 AppCompatActivity),未见状态栏。
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
在Android3.0中,View添加了一个重要的方法:View.setSystemUiVisibility(int),用于控制一些窗口装饰元素的显示,并添加了
两个Flag用于控制Status Bar的显示与隐藏。
一般是这么用的
View decorView = getWindow().getDecorView();
int uiOptions = View.STATUS_BAR_VISIBLE;
decorView.setSystemUiVisibility(uiOptions);
View.SYSTEM_UI_FLAG_IMMERSIVE 和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 搭配使用,使用 SYSTEM_UI_FLAG_HIDE_NAVIGATION 后,导航栏消失,当用户交互时(例如点击一个 button),导航栏又会出现,添加 View.SYSTEM_UI_FLAG_IMMERSIVE 后,交互时导航栏不会出现,但是会底部滑动导航栏仍会出现。
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 和 View.SYSTEM_UI_FLAG_FULLSCREEN 配合使用:状态栏半透明,顶部向下滑动出现,过一段时间消失。
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 配合使用:导航栏半透明,交互时,导航栏不出现,底部向上滑动出现,过一段时间消失。
FLAG_TRANSLUCENT_STATUS
当使用这个flag时SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN会被自动添加,同时,设置FLAG_TRANSLUCENT_STATUS也会影响到StatusBar的背景色,但并没有固定的表现:
google 你到底要闹哪样?
FLAG_TRANSLUCENT_NAVIGATION
当使用这这个个flag时SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION会被自动添加。同时,设置FLAG_TRANSLUCENT_STATUS也会影响到 NavigationBar 的背景色,效果与 FLAG_TRANSLUCENT_STATUS 相同
在Android6以后,我们只要给SystemUI加上SYSTEM_UI_FLAG_LIGHT_STATUS_BAR这个flag,就可以让字体和图标变为黑色。
在布局内容延伸到状态栏和导航栏时,我们可以给 View 设置 fitSystemWindows 属性,它是一个 boolean 值,可以在xml里直接设置android:fitsSystemWindows="true",也可以通过View#setFitsSystemWindows(boolean fitSystemWindows)在java代码中设置。设置后,空调会调整自己的 padding 用于避开系统控件。
工作原理:
Android系统组件例如状态栏、NavBar、键盘所占据的空间称为界面的WindowInsets,Android系统会在特定的时机从根View派发WindowInsets(深度优先)。一旦有一个View 的 fitSystemWindows 设置为 true,它就会根据WindowInsets来调整自己的 padding,并消耗WindowInsets,不在向下分发 WindowInsets,那么WindowInsets的派发过程就结束了。
需要注意的是:
采用这个效果的应用主要是 Material Design 设计风格的 App,表现形式为:
实现这样的风格很简单:
xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimaryitem>
<item name="colorPrimaryDark">@color/colorPrimaryDarkitem>
<item name="colorAccent">@color/colorAccentitem>
<item name="android:windowDrawsSystemBarBackgrounds">trueitem>
<item name="android:statusBarColor">@android:color/transparentitem>
style>
resources>
需要注意的是:
<item name="android:windowDrawsSystemBarBackgrounds">trueitem>
和
<item name="android:windowTranslucentStatus">trueitem>
不能同时设置为 true,否则设置的颜色失效。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(color);
}
效果和 Material Design 风格类似,设置方法和Material Design 风格相同。
效果:
曾经,想做个 material design 风格的侧边栏效果,那是相当的复杂,可以看看这篇文章,现在(support 库最新版本 26.1.0),给 DrawerLayout 设置 fitSystemWindows 为 true,系统就帮你把所有的事办好了,当然包括了老版本的兼容(google 大法好)。
效果:
5.0+:渐变
5.0-:大黑边
实现:
v21 的style
<item name="android:windowDrawsSystemBarBackgrounds">trueitem>
<item name="android:statusBarColor">@android:color/transparentitem>
或者
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.transparent));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
不同版本设置不同的布局(代码,xml 均可)
5.0+:在布局顶部加上有渐变效果背景的 View,渐变效果可以使用 shape 实现。
5.0-:正常布局。
欢迎,登录,全屏视频播放等界面可能会使用这样的效果。
常见的效果有:
视频全屏播放:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
全屏欢迎页面:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
类似qq的登录页面
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
一般这么干的都是将状态栏设计为浅色的。因为仅 6.0+ 和 小米 魅族支持修改状态栏颜色。5.0 版本会因为浅色状态栏看不清状态栏信息。最好还是让设计改设计稿吧!非要这么做的话,就只有为 5.0 单独设计了,适配 5.0-, 5.0+, 6.0+,这酸爽。
同渐变效果,仅最后一步将添加渐变 view 改为 添加 ImageView 即可。
github 有一些很火热的库,使用了 FLAG_TRANSLUCENT_STATUS 特性,将状态栏适配到了 4.4,上文已指出 FLAG_TRANSLUCENT_STATUS 在不同平台显示效果存在差异,不能保证较为一致的视觉效果,所以状态栏要玩出花样最合适的版本是 5.0+, 5.0- 统一大黑边就可以了。