概念
- 全屏模式
- 變色狀態(tài)欄模式
- 背景全屏+變色狀態(tài)欄模式
- 圖片全屏+變色狀態(tài)欄模式
- ContentView: activity.findViewById(Window.ID_ANDROID_CONTENT) 獲取的 View , 即 setContentView 方法所設(shè)置的 View, 實質(zhì)為 FrameLayout.
- ContentParent: ContentView 的 parent , 實質(zhì)為 LinearLayout.
- ChildView: ContentView 的第一個子 View ,即布局文件中的 layout.
相關(guān)函數(shù)
-
fitsSystemWindows
, 該屬性可以設(shè)置是否為系統(tǒng) View 預(yù)留出空間, 當設(shè)置為 true 時,會預(yù)留出狀態(tài)欄的空間. -
ContentView
, 實質(zhì)為 ContentFrameLayout, 但是它的 dispatchFitSystemWindows 重寫了 fitsSystemWindows 方法, 所以對其設(shè)置 fitsSystemWindows 無效. -
ContentParent
, 實質(zhì)為 FitWindowsLinearLayout, 里面第一個 View 是 ViewStubCompat, 如果主題沒有設(shè)置 title ,它就不會 inflate .第二個 View 就是 ContentView. -
setClipToPadding
: 保持padding, true為保持
概述
- 先看一下四張圖
-
4.4.4默認
-
4.4.4 去掉 ActionBar
-
5.0 默認
-
5.0去掉 ActionBar
- DecorView結(jié)構(gòu):
--DecorView == extends FrameLayout
------View (4.4在這自定義個偽狀態(tài)欄)
------LinearLayout
----------ViewStub
----------FrameLayout
--------------FitWindowsLinearLayout(style設(shè)置了不帶toolbar)
------------------ViewStubCompat
------------------ContentFrameLayout == ContentView
--------------ActionBarOverlayLayout(style設(shè)置了帶toolbar)
------------------ContentFrameLayout == ContentView
------------------ActionBarContainer
------view(5.0才有的statusbarbackground, 系統(tǒng)級, getChildAt找不到,得finsViewById找)
------view(5.0才有的navigationbackground, 系統(tǒng)級, getChildAt找不到,得finsViewById找)
總結(jié)一下:
可以看出 DecorView 作為根布局, 持有一個 LinearLayout,
* 5.0在LinearLayout下持有四個View, 兩個系統(tǒng)級的 View(StatusBar 和 Navigation), 和兩個 FrameLayout, 一個是ViewStub, 一個是給了 ContentFraneLayout + ActionBar(當設(shè)置不需要 ActionBar 時, 是ViewStubCompat).
* 4.4在LinearLayout下只有兩個View, 可以推出5.0可以直接```setStatusBarColor```是因為多了這倆view, 那我們只要在 LinearLayout 中插入一個 view 就可以學(xué)著5.0的樣子, 讓ContentFraneLayout下移.
4.4 以下放棄
4.4.4 kitcat
谷歌在 Android 的 Window 屬性里添加了可以讓狀態(tài)欄和導(dǎo)航欄被穿透(ContentView覆蓋StatusBar)的屬性
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
- 建議使用代碼設(shè)置(國產(chǎn)ROM有迷之bug)
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
全屏模式
- 給 Window 添加 FLAG_TRANSLUCENT_STATUS
- 給 ContentView 的子 view 設(shè)置 setFitsSystemWindows
FLAG_TRANSLUCENT_STATUS 效果:
自動設(shè)置了 SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 讓 ContentView 滿屏
變色狀態(tài)欄模式
- 給 Window 添加 FLAG_TRANSLUCENT_STATUS
- 給 DecorView 添加一個偽狀態(tài)欄
- 給 ContentView 的子 view 全部設(shè)置 setFitsSystemWindows
背景全屏+變色狀態(tài)欄模式
- 給 Window 添加 FLAG_TRANSLUCENT_STATUS
- 給 ContentView 的子 view 全部設(shè)置 fitsSystemWindows, 空出StatusBar的高給偽狀態(tài)欄
- 給 ContentView 添加一個偽 StatusBar
圖片全屏+變色狀態(tài)欄模式
- 給 Window 添加 FLAG_TRANSLUCENT_STATUS
- 給 ContentView 添加一個偽 StatusBar
- 如果是 Imageview 浮在布局上, 即下一個布局也懟上了 StatusBar, 需要手動給后續(xù)布局加 topMargin
5.0 LOLLIPOP
比起 4.4, 不需要 FLAG_TRANSLUCENT_STATUS, 因為谷歌又?提供了setStatusBarColor
, 不過默認 StatusBar 的會添加半透明灰條, 所以還得改下 StatusBar 的顏色為透明
全屏模式:
- 給 Window 設(shè)置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 讓 ContentView 懟到頂
- 給 Window 設(shè)置
setStatusBarColor
修改透明顏色
變色狀態(tài)欄模式
- 給 Window 設(shè)置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 讓 ContentView 懟到頂
- 給 windiw 設(shè)置
setStatusBarColor
修改指定顏色
背景全屏+變色狀態(tài)欄模式
- 給 Window 設(shè)置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 讓 ContentView 懟到頂
- 給 Window 設(shè)置
setStatusBarColor
修改透明顏色 - 給 ContentView 的子 view 全部設(shè)置 fitsSystemWindows, 空出StatusBar的高給偽狀態(tài)欄
- 給 ContentView 添加偽 StatusBar
圖片全屏+變色狀態(tài)欄模式(3,4步和4.4處理方式一樣)
- 給 StatusBar 設(shè)置透明
- 給 DecorView 設(shè)置 SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
是不是很眼熟, 對, 就是FLAG_TRANSLUCENT_STATUS自動附帶的設(shè)置, 不過5.0 可以直接改 StatusBar 的顏色了, 不需要 TRANSLUCENT_STATUS
- 給 ContentView 添加偽 StatusBar
- 如果是 Imageview 浮在布局上, 即下一個布局也懟上了 StatusBar, 需要手動給后續(xù)布局加 topMargin
特殊需求:
如果一個 StatusBar 可變色的 acitivy, 加入圖片全屏 + 變色StatusBar 的 fragment/或 StatusBar 聯(lián)動的 fragment 也就是當 StatusBar 和 fragment 一體, 建議?此 fragment 替換為 activity, 雖然可以?實現(xiàn), 但是需要頁面繪制兩遍不說, 二是 StatusBar 是在頁面出現(xiàn)后加入的. 如果項目一開始就有這個需求, 那么在全部fragment?的xml中加狀態(tài)欄高的view
fragment中的沉浸式
思路:
如果需要 StatusBar 和 fragment 一起聯(lián)動, 需要多兩步
- 在fragment的xml中添加一個view(StatusBar_view_height).
- xml中設(shè)置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一個處理思路
實現(xiàn)
Tips:
自定義Theme 運行時是先找自己版本號對應(yīng)的styles, 如果沒有那就去找無版本號的styles里的. 所以一定要在無版本號的styles里寫上自定義Theme, 哪怕里面沒有東西, 不然直接崩
推薦通過代碼修改, 單純的依靠theme也可以, 但是不如代碼直觀, 也不便于控制
1. theme中需要做的鋪墊
a. 通過代碼里設(shè)置
- 去掉自帶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
到底在哪兒設(shè)置- 在 theme 中設(shè)置是對整個 Window, 導(dǎo)致Toast文字內(nèi)容 上浮, 建議在代碼里設(shè)置
- 當前布局的最外層和 SystemWindow 接觸, 所以給最外層的 view 設(shè)置 fitsSystemWindows 才能有效果
- WindowTranslucentStatus
到底設(shè)置true還是false<item name="android:WindowTranslucentStatus">true</item> <item name="android:WindowTranslucentNavigation">true</item> <!--Android 5.x開始需要把顏色設(shè)置透明,否則導(dǎo)航欄會呈現(xiàn)系統(tǒng)默認的淺灰色--> <item name="android:StatusBarColor">@android:color/transparent</item>
- 華為7.0在theme被設(shè)置成這樣時, StatusBar被摸過后就半透明的掛在頭上了, 模擬器則是能直接看到半透明的StatusBar
<item name="android:WindowTranslucentStatus">false</item> <item name="android:WindowTranslucentNavigation">true</item> <!--Android 5.x開始需要把顏色設(shè)置透明,否則導(dǎo)航欄會呈現(xiàn)系統(tǒng)默認的淺灰色--> <item name="android:StatusBarColor">@android:color/transparent</item>
- 華為7.0在theme被設(shè)置成這樣時, StatusBar怎么摸都沒事兒, 模擬器也是看不見StatusBar的
TODO
參考