Android-transulcent-status-bar
透明状态栏适配.主要适用场景为一个Activity
多个tab
在不同状态栏模式下切换.
Github Demo 链接: StatusBarCompat
参考文章:
- 由沉浸式状态栏引发的血案
- Translucent System Bar 的最佳实践
- 该使用 fitsSystemWindows 了!
- Android 透明状态栏实现方案
- 更简单更全的material design状态栏
首先强调,对于状态栏的处理有两种不同的方式, 这里从Translucent System Bar 的最佳实践直接盗了两张图做对比~.
全屏( ContentView 可以进入状态栏) | 非全屏 ( ContentView 与状态栏分离, 状态栏直接着色) |
---|---|
先定义几个名词:
- 全屏模式: 左边图所示.
- 着色模式: 右边图所示.
- ContentView:
activity.findViewById(Window.ID_ANDROID_CONTENT)
获取的 View , 即setContentView
方法所设置的 View, 实质为FrameLayout
. - ContentParent:
ContentView
的 parent , 实质为LinearLayout
. - ChildView:
ContentView
的第一个子 View ,即布局文件中的 root layout .
再介绍一下相关的函数:
fitsSystemWindows
, 该属性可以设置是否为系统 View 预留出空间, 当设置为 true 时,会预留出状态栏的空间.ContentView
, 实质为ContentFrameLayout
, 但是重写了dispatchFitSystemWindows
方法, 所以对其设置fitsSystemWindows
无效.ContentParent
, 实质为FitWindowsLinearLayout
, 里面第一个 View 是ViewStubCompat
, 如果主题没有设置 title ,它就不会 inflate .第二个 View 就是ContentView
.requestApplyInsets()
, 当窗口(Window)大小改变了,通知 View 去消费窗口的改变.FLAG_TRANSLUCENT_STATUS
, 设置全屏的标志位, 此时界面可以延伸到状态栏.
5.0以上的处理:
自5.0引入 Material Design ,状态栏对开发者更加直接,可以直接调用 setStatusBarColor
来设置状态栏的颜色.
**着色模式: **
通过查看 setStatusBarColor()
方法的文档,发现在调用该方法时需要设置以下属性:
- 添加
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
Flag(绘制系统栏). - 清除
FLAG_TRANSLUCENT_STATUS
Flag(透明状态栏). - 调用
setStatusBarColor()
设置状态栏颜色.
**全屏模式: **
由于 5.0 以上为状态栏添加了一个阴影, 所以为全屏模式添加了是否隐藏状态栏阴影的方法.
隐藏阴影
- 像着色模式一样添加 flag ,然后通过
setStatusBarColor()
设置颜色为透明. - 通过
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
隐藏状态栏颜色.
- 像着色模式一样添加 flag ,然后通过
显示阴影
- 设置
FLAG_TRANSLUCENT_STATUS
来隐藏状态栏. - 通过
setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE)
来恢复默认状态栏样式.
- 设置
4.4-5.0的处理:
4.4-5.0因为没有直接的 API 可以调用,需要自己兼容处理.参考了网上的解决方法及结合我自己遇到的坑,最后想出的解决办法如下:
着色模式
- 向
DecorView
中添加一个 View, 高度为状态栏的高度(反射获取). - 将
ChildView
的 marginTop 加上状态栏的高度,以此来模拟fitsSystemWindows
. - 设置
ChildView
的 fitsSystemWindow 为 false, 不预留系统栏位置. - 为
DecorView
设置一个 tag, 防止重复添加 View.
这里与其他地方不同的是:
- 向
ContentView
添加 View 在部分机型(华为)上没有效果. - 向
ContentParent
上添加 View 会有一条黑线. - 使用 marginTop 而不是
fitsSystemWindows
是因为无法在**不重启 Activity **的情况下切换 root layout 的fitsSystemWindows
属性, 即直接设置不会生效, 所以用 marginTop 来模拟.
全屏模式
- 设置
ChildView
的 fitsSystemWindow 为 false, 不预留系统栏位置. - 如果在
ChildView
的 marginTop 中添加了状态栏的高度, 则移除. - 设置 tag, 防止重复移除.
** CollaspingToolbarLayout **
这个 support 包中的控件, 由于重写了 onApplySystemInsets()
方法, 按照我所理解的状态栏模式, 它在滑动时在两种模式中切换, 对此我的兼容方法就是让其处于 着色模式 下,在滑动时保持状态栏颜色不变. 当然有更好的解决办法, 但我这里为了方便调用(只需要传递 Activity 对象), 就用了比较简单的处理方法.
CollapsingToolbarLayout
support 包中提供的 CollapsingToolbarLayout
, 在使用的时候大概的布局是这样的(参考 CheeseSquare ):
<CoordinatorLayout
android:fitsSystemWindows="true">
<AppBarLayout
android:fitsSystemWindows="true">
<CollapsingToolbarLayout
android:fitsSystemWindows="true">
<View
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax"/>
<ToolBar
app:layout_collapseMode="pin"/>
</CollapsingToolbarLayout>
<AppBarLayout/>
<View
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</CoordinatorLayout>
在适配的时候主要遇到以下几个问题:
- 如果按照我上面介绍的方式来说, 它在显示图片的时候是
全屏模式
, 在显示Toolbar
的时候是着色模式
. CollapsingToolbarLayout
的内部在 5.0 及以上的版本中通过OnApplyWindowInsetsListener()
中获取的 Insets 对象, 在 Layout 的过程中将 View 向下偏移了, 所以它在 5.0 及以上系统中可以占据状态栏, 在 4.4 系统上则不能.- 仿照 CheeseSquare 这个库中的写法,
CollapsingToolbarLayout
需要设置FitsSystemWindow
为 true, 而我在前面兼容全屏模式
和着色模式
的时候, 都是设置FitsSystemWindow
为 false. 同时目前我没找到方法在不重启 Activity 的情况下切换FitsSystemWindow
.
在参考了网上的文章后,最后决定通过以下方法来处理.
4.4版本:
- 变为全屏模式,设置 View 的
fitsSystemWindow
为 false, 这一步可以使CollapsingToolbarLayout
占据状态栏,Toolbar
也是. - 改变
Toolbar
的高度, 加上状态栏的高度, 让Toolbar
挡住状态栏位置, 同时为Toolbar
添加 paddingTop , 这样就可以让 title 正常显示. - 添加假的
StatusView
模拟状态栏颜色, 通过AppBarLayout
的OnOffsetChangedListener()
监听AppBarLayout
的滑动, 使StatusView
跟随CollapsingToolbarLayout
的显示隐藏.
- 变为全屏模式,设置 View 的
5.0及以上版本:
- 变为全屏模式,设置 View 的
fitsSystemWindow
为 false, 这一步可以使CollapsingToolbarLayout
占据状态栏,Toolbar
也是. - 改变
Toolbar
的高度, 加上状态栏的高度, 让Toolbar
挡住状态栏位置, 同时为Toolbar
添加 paddingTop , 这样就可以让 title 正常显示. 这都和 4.4 一样. - 为
CollapsingToolbarLayout
设置OnApplyWindowInsetsListener()
使其正常 Layout ,因为此时CollapsingToolbarLayout
已经显示到状态栏了, 不需要在 Layout 过程中向下偏移, 但是此时collapsingToolbarLayout.setStatusBarScrimColor()
也就无效了. - 通过
AppBarLayout
的OnOffsetChangedListener()
监听AppBarLayout
的滑动, 利用setStatusBarColor()
设置状态栏颜色即可.
- 变为全屏模式,设置 View 的
关于博客和库
博客主要提供思路解析,因为博客的通知不及时,大家有问题有想法想交流时还请在 Github issues 页联系.