首先: android 的透明状态栏和沉浸式是两个不同的东西,但是又相互交错,不要混淆。透明状态栏是指将状态栏设置为透明或者半透明,沉浸式是指,将页面的布局“沉浸”在状态栏下面,如果这时候将状态栏设置为透明,那么状态栏和手机页面看以来是一个整体,增大了屏幕的利用空间。如果设置了沉浸式状态栏不透明,毫无疑问布局将会被状态栏遮挡。
在之前先讲讲Android的主题设置,和将状态栏设置透明带来的变化。
对于现在开发项目我们一般使用的是 Theme.AppCompat.xxx兼容包里面的主题
<style name="AppTheme1" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorPrimary</item>
</style>
为了兼容不同版本,会建立多个版本兼容的文件夹
比如:
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorPrimary</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
前三个属性分别表示表示的颜色用一张经典的图来对应表示:
分别代表toolbar的颜色、状态栏的颜色、输入法和radiobuttion等的颜色,但是需要注意的是:
在5.0以下的版本,状态栏的颜色通过主题设置是没有用的,用以上的主题属性来设置状态栏颜色,在5.x以下是黑色,自己可以试试。
后三个属性是来设置透明状态栏的,android:windowTranslucentStatus、android:windowTranslucentNavigation是4.4以后才有的属性,android:statusBarColor是5.0以后才有的属性,所以才要分为几个value文件夹来存放不同的主题,好在as现在非常智能,如果你在兼容低版本的情况下,用了高版本的api会发出警告。
设置状态栏透明
那么设置状态栏透明又会是什么样子呢?(分析4.4以上的版本)
有两种方式设置状态栏透明,第一种是上面的通过改变主题的方式,这里贴出value-v19、v21的主题参数
v19
<style name="AppTheme1" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorPrimary</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
========
v21
<style name="AppTheme1" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorPrimary</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
主要区别只一个用了actionbar主题,一个没用,这里是为了尝试看到更多变化的效果,对这里透明状态栏没影响。
正对以上运行效果。说明下:
- 4.4版本和5.x版本设置状态栏是有差异的,4.4的状态栏和底部导航栏都变半透明,但是颜色是渐变的,而5.x以上是变灰色
- windowTranslucentStatus属性改变状态栏成半透明,并且布局网上顶,充满全屏
- windowTranslucentNavigation属性改变底部导航栏颜色为半透明
- statusBarColor 5.x才有设置状态栏颜色,4.x不是不能设置颜色的。
这里对上面扩展下:
为什么setContentView的布局会顶上去呢?再来一张窗口的层级的经典图片
statubar状态栏是系统窗口,DecorView是视图的顶级窗口,继承自FramLayout,他的子View一个是actionbar,和一个id为content的FramLyout,这个content就是setContentView的那个布局,通过AS的工具也可以看出来。
至于为什么设置了透明主题属性就会把contentView顶上去呢?这里没有去探究源码,暂且就这么认为吧——如果设置了透明状态栏,decorview和content之间的margin为0,这时候content布局的大小就是整个屏幕的大小;如果没有设置,则margin为状态栏的高度加上actionbar的高度(如果有)。但是actionbar没有顶上去,但是有什么方法不让顶上去呢?有两种方法。
1、将跟布局添加:android:fitsSystemWindows="true|false"
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true"
android:gravity="start"
android:background="#ffffff"
tools:context="com.xc.test.MainActivity">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitStart"
android:src="@drawable/aaa"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</android.support.v7.widget.LinearLayoutCompat>
2、代码设置
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
注意:android:fitsSystemWindows这个属性只有在主题中设置了[windowTranslucentStatus|windowTranslucentNavigation]属性或者代码中调用window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);才会生效。(我目前的验证是这样)
利用代码设置状态栏透明
// 设置状态栏全透明
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//设置根布局顶上去
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
在这里看到6.x的模拟器状态栏为什么不是灰色呢?最后找到了答案,原来通过代码设置的透明和通过主题设置是有区别的
状态栏着色
- 5.x以上的版本
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.setStatusBarColor(setStatusBarColor());
window.setStatusBarColor(setStatusBarColor());这个方法设置状态栏的颜色5.x以后才有的api,4.4版本需要做特殊处理。
大家发现没有,我一直在6.x的模拟器上设置了一个actionBar,然而这个actionbar没有沉浸到状态栏下面,正是如此,我们只能舍弃actionbar使用toolbar了,在页面的布局中加入toolbar
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimaryDark"
app:title="toobar"
>
</android.support.v7.widget.Toolbar>
toolbar随着布局顶到状态栏下面,其实toolbar有两种用法:
一种是设置没有actionbar的主题(你也可以设置,但是这样会重叠),将toolbar像上面一样嵌入布局中,toolbar就是一个普通的布局,实质上toolbar是继承的ViewGroup,这样没毛病。
另一种是setSupportActionBar(toolbar),让toolbar替代actionbar,如果是这样的话,主题必须是noActionBar的,不然抛异常,这样子toolbar就会继承actionbar的一些特性,比如设置透明状态栏之后不会将布局顶上去,而且还为你把toolbar填充了高度。当然前提是不能调用window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);如果调用了这个方法,照样会顶上去的,也可以用fitsSystemWindows来配合使用,多尝试。
就这样,当状态栏为透明,toolbar又顶上去了,这样就显得整个主题风格一致,这就是沉浸式。
还有就是app最上端为图片的时候希望这样设计:
这叫透明状态栏,反正也没个规范的说法,我就这么叫的。
4.4状态栏着色
4.4版本唯一一个和5.x版本不一样的地方就是4.4没有改变状态栏颜色的api,只有改变透明度的api,那怎么解决这个问题呢?
我们都知道,整个app展现在我们眼前的最外层的视图为DecorView,实质上是一个FramLayout,状态栏是系统的窗口,覆盖在DecorView之上的,DecorView里面有我们的content,既然是这样,我们可以在DecorView里面加一个布局,覆盖在content之上,通过设置状态栏透明,改变这个View的颜色,这样就造成了改变状态栏颜色的假象。这些事情早就有人遭了轮子,在这里就不重复了。
StatusBarUtil
总结:
- 4.4以上才有沉浸式状态栏
- 设置状态栏透明或者任意颜色(可以通过主题和代码方法)使得布局顶到状态栏下面
- toolbar替换actionbar使得沉浸式得以实现
下一篇写toolbar的使用和沉浸式BaseActivity基类的封装