Day20-沉浸式状态栏
概念
- 全屏模式
- 变色状态栏模式
- 背景全屏+变色状态栏模式
- 图片全屏+变色状态栏模式
- ContentView: activity.findViewById(Window.ID_ANDROID_CONTENT) 获取的 View , 即 setContentView 方法所设置的 View, 实质为 FrameLayout.
- ContentParent: ContentView 的 parent , 实质为 LinearLayout.
- ChildView: ContentView 的第一个子 View ,即布局文件中的 layout.
相关函数
-
fitsSystemWindows
, 该属性可以设置是否为系统 View 预留出空间, 当设置为 true 时,会预留出状态栏的空间. -
ContentView
, 实质为 ContentFrameLayout, 但是它的 dispatchFitSystemWindows 重写了 fitsSystemWindows 方法, 所以对其设置 fitsSystemWindows 无效. -
ContentParent
, 实质为 FitWindowsLinearLayout, 里面第一个 View 是 ViewStubCompat, 如果主题没有设置 title ,它就不会 inflate .第二个 View 就是 ContentView. -
setClipToPadding
: 保持padding, true为保持
概述
- 先看一下四张图
- 4.4.4默认
- 4.4.4 去掉 ActionBar
- 5.0 默认
- 5.0去掉 ActionBar
- DecorView结构:
--DecorView == extends FrameLayout
------View (4.4在这自定义个伪状态栏)
------LinearLayout
----------ViewStub
----------FrameLayout
--------------FitWindowsLinearLayout(style设置了不带toolbar)
------------------ViewStubCompat
------------------ContentFrameLayout == ContentView
--------------ActionBarOverlayLayout(style设置了带toolbar)
------------------ContentFrameLayout == ContentView
------------------ActionBarContainer
------view(5.0才有的statusbarbackground, 系统级, getChildAt找不到,得finsViewById找)
------view(5.0才有的navigationbackground, 系统级, getChildAt找不到,得finsViewById找)
总结一下:
可以看出 DecorView 作为根布局, 持有一个 LinearLayout,
* 5.0在LinearLayout下持有四个View, 两个系统级的 View(StatusBar 和 Navigation), 和两个 FrameLayout, 一个是ViewStub, 一个是给了 ContentFraneLayout + ActionBar(当设置不需要 ActionBar 时, 是ViewStubCompat).
* 4.4在LinearLayout下只有两个View, 可以推出5.0可以直接```setStatusBarColor```是因为多了这俩view, 那我们只要在 LinearLayout 中插入一个 view 就可以学着5.0的样子, 让ContentFraneLayout下移.
4.4 以下放弃
4.4.4 kitcat
谷歌在 Android 的 Window 属性里添加了可以让状态栏和导航栏被穿透(ContentView覆盖StatusBar)的属性
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
- 建议使用代码设置(国产ROM有迷之bug)
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
全屏模式
- 给 Window 添加 FLAG_TRANSLUCENT_STATUS
- 给 ContentView 的子 view 设置 setFitsSystemWindows
FLAG_TRANSLUCENT_STATUS 效果:
自动设置了 SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 让 ContentView 满屏
变色状态栏模式
- 给 Window 添加 FLAG_TRANSLUCENT_STATUS
- 给 DecorView 添加一个伪状态栏
- 给 ContentView 的子 view 全部设置 setFitsSystemWindows
背景全屏+变色状态栏模式
- 给 Window 添加 FLAG_TRANSLUCENT_STATUS
- 给 ContentView 的子 view 全部设置 fitsSystemWindows, 空出StatusBar的高给伪状态栏
- 给 ContentView 添加一个伪 StatusBar
图片全屏+变色状态栏模式
- 给 Window 添加 FLAG_TRANSLUCENT_STATUS
- 给 ContentView 添加一个伪 StatusBar
- 如果是 Imageview 浮在布局上, 即下一个布局也怼上了 StatusBar, 需要手动给后续布局加 topMargin
5.0 LOLLIPOP
比起 4.4, 不需要 FLAG_TRANSLUCENT_STATUS, 因为谷歌又�提供了setStatusBarColor
, 不过默认 StatusBar 的会添加半透明灰条, 所以还得改下 StatusBar 的颜色为透明
全屏模式:
- 给 Window 设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 让 ContentView 怼到顶
- 给 Window 设置
setStatusBarColor
修改透明颜色
变色状态栏模式
- 给 Window 设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 让 ContentView 怼到顶
- 给 windiw 设置
setStatusBarColor
修改指定颜色
背景全屏+变色状态栏模式
- 给 Window 设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 让 ContentView 怼到顶
- 给 Window 设置
setStatusBarColor
修改透明颜色 - 给 ContentView 的子 view 全部设置 fitsSystemWindows, 空出StatusBar的高给伪状态栏
- 给 ContentView 添加伪 StatusBar
图片全屏+变色状态栏模式(3,4步和4.4处理方式一样)
- 给 StatusBar 设置透明
- 给 DecorView 设置 SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
是不是很眼熟, 对, 就是FLAG_TRANSLUCENT_STATUS自动附带的设置, 不过5.0 可以直接改 StatusBar 的颜色了, 不需要 TRANSLUCENT_STATUS
- 给 ContentView 添加伪 StatusBar
- 如果是 Imageview 浮在布局上, 即下一个布局也怼上了 StatusBar, 需要手动给后续布局加 topMargin
特殊需求:
如果一个 StatusBar 可变色的 acitivy, 加入图片全屏 + 变色StatusBar 的 fragment/或 StatusBar 联动的 fragment 也就是当 StatusBar 和 fragment 一体, 建议�此 fragment 替换为 activity, 虽然可以�实现, 但是需要页面绘制两遍不说, 二是 StatusBar 是在页面出现后加入的. 如果项目一开始就有这个需求, 那么在全部fragment�的xml中加状态栏高的view
fragment中的沉浸式
思路:
如果需要 StatusBar 和 fragment 一起联动, 需要多两步
- 在fragment的xml中添加一个view(StatusBar_view_height).
- xml中设置StatusBar_view_height的值
- <dimen name="StatusBar_view_height">0dp</dimen>
v19 - <dimen name="StatusBar_view_height">25dp</dimen>
vw820dp - <dimen name="activity_horizontal_margin">64dp</dimen>
抽屉
和activity一个处理思路
实现
Tips:
自定义Theme 运行时是先找自己版本号对应的styles, 如果没有那就去找无版本号的styles里的. 所以一定要在无版本号的styles里写上自定义Theme, 哪怕里面没有东西, 不然直接崩
推荐通过代码修改, 单纯的依靠theme也可以, 但是不如代码直观, 也不便于控制
1. theme中需要做的铺垫
a. 通过代码里设置
- 去掉自带actionBar
<item name="WindowActionBar">false</item> <item name="android:WindowActionBar">false</item> <item name="WindowNoTitle">true</item>
- 去掉打开时先加载一闪而过的 空白背景+默认StatusBar 的默认背景
<item name="android:WindowIsTranslucent">true</item> <item name="android:WindowBackground">@android:color/transparent</item>
2. 代码:
https://github.com/laobie/StatusBarUtil
踩坑
- fitsSystemWindows
到底在哪儿设置- 在 theme 中设置是对整个 Window, 导致Toast文字内容 上浮, 建议在代码里设置
- 当前布局的最外层和 SystemWindow 接触, 所以给最外层的 view 设置 fitsSystemWindows 才能有效果
- WindowTranslucentStatus
到底设置true还是false<item name="android:WindowTranslucentStatus">true</item> <item name="android:WindowTranslucentNavigation">true</item> <!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色--> <item name="android:StatusBarColor">@android:color/transparent</item>
- 华为7.0在theme被设置成这样时, StatusBar被摸过后就半透明的挂在头上了, 模拟器则是能直接看到半透明的StatusBar
<item name="android:WindowTranslucentStatus">false</item> <item name="android:WindowTranslucentNavigation">true</item> <!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色--> <item name="android:StatusBarColor">@android:color/transparent</item>
- 华为7.0在theme被设置成这样时, StatusBar怎么摸都没事儿, 模拟器也是看不见StatusBar的
TODO
参考