Android 沉浸式狀態(tài)欄原理

首先: android 的透明狀態(tài)欄和沉浸式是兩個(gè)不同的東西但校,但是又相互交錯(cuò)告材,不要混淆。透明狀態(tài)欄是指將狀態(tài)欄設(shè)置為透明或者半透明驳规,沉浸式是指,將頁面的布局“沉浸”在狀態(tài)欄下面创肥,如果這時(shí)候?qū)顟B(tài)欄設(shè)置為透明达舒,那么狀態(tài)欄和手機(jī)頁面看以來是一個(gè)整體值朋,增大了屏幕的利用空間。如果設(shè)置了沉浸式狀態(tài)欄不透明巩搏,毫無疑問布局將會(huì)被狀態(tài)欄遮擋昨登。

在之前先講講Android的主題設(shè)置,和將狀態(tài)欄設(shè)置透明帶來的變化贯底。
對于現(xiàn)在開發(fā)項(xiàng)目我們一般使用的是 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>

為了兼容不同版本丰辣,會(huì)建立多個(gè)版本兼容的文件夾


image.png

比如:

        <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>

前三個(gè)屬性分別表示表示的顏色用一張經(jīng)典的圖來對應(yīng)表示:

image.png

分別代表toolbar的顏色、狀態(tài)欄的顏色禽捆、輸入法和radiobuttion等的顏色笙什,但是需要注意的是:
在5.0以下的版本,狀態(tài)欄的顏色通過主題設(shè)置是沒有用的胚想,用以上的主題屬性來設(shè)置狀態(tài)欄顏色琐凭,在5.x以下是黑色,自己可以試試浊服。

后三個(gè)屬性是來設(shè)置透明狀態(tài)欄的统屈,android:windowTranslucentStatus、android:windowTranslucentNavigation是4.4以后才有的屬性牙躺,android:statusBarColor是5.0以后才有的屬性愁憔,所以才要分為幾個(gè)value文件夾來存放不同的主題,好在as現(xiàn)在非常智能孽拷,如果你在兼容低版本的情況下吨掌,用了高版本的api會(huì)發(fā)出警告。

設(shè)置狀態(tài)欄透明

那么設(shè)置狀態(tài)欄透明又會(huì)是什么樣子呢脓恕?(分析4.4以上的版本)
有兩種方式設(shè)置狀態(tài)欄透明膜宋,第一種是上面的通過改變主題的方式,這里貼出value-v19进肯、v21的主題參數(shù)

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>

主要區(qū)別只一個(gè)用了actionbar主題激蹲,一個(gè)沒用棉磨,這里是為了嘗試看到更多變化的效果江掩,對這里透明狀態(tài)欄沒影響。


image.png

正對以上運(yùn)行效果乘瓤。說明下:

  • 4.4版本和5.x版本設(shè)置狀態(tài)欄是有差異的环形,4.4的狀態(tài)欄和底部導(dǎo)航欄都變半透明,但是顏色是漸變的衙傀,而5.x以上是變灰色
  • windowTranslucentStatus屬性改變狀態(tài)欄成半透明抬吟,并且布局網(wǎng)上頂,充滿全屏
  • windowTranslucentNavigation屬性改變底部導(dǎo)航欄顏色為半透明
  • statusBarColor 5.x才有設(shè)置狀態(tài)欄顏色统抬,4.x不是不能設(shè)置顏色的火本。

這里對上面擴(kuò)展下:
為什么setContentView的布局會(huì)頂上去呢危队?再來一張窗口的層級的經(jīng)典圖片


image.png

statubar狀態(tài)欄是系統(tǒng)窗口,DecorView是視圖的頂級窗口钙畔,繼承自FramLayout茫陆,他的子View一個(gè)是actionbar,和一個(gè)id為content的FramLyout擎析,這個(gè)content就是setContentView的那個(gè)布局簿盅,通過AS的工具也可以看出來。

image.png

至于為什么設(shè)置了透明主題屬性就會(huì)把contentView頂上去呢?這里沒有去探究源碼揍魂,暫且就這么認(rèn)為吧——如果設(shè)置了透明狀態(tài)欄桨醋,decorview和content之間的margin為0,這時(shí)候content布局的大小就是整個(gè)屏幕的大邢终喜最;如果沒有設(shè)置,則margin為狀態(tài)欄的高度加上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、代碼設(shè)置

window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

注意:android:fitsSystemWindows這個(gè)屬性只有在主題中設(shè)置了[windowTranslucentStatus|windowTranslucentNavigation]屬性或者代碼中調(diào)用window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);才會(huì)生效蔗包。(我目前的驗(yàn)證是這樣)

利用代碼設(shè)置狀態(tài)欄透明
// 設(shè)置狀態(tài)欄全透明
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //設(shè)置根布局頂上去
            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);
        }
image.png

在這里看到6.x的模擬器狀態(tài)欄為什么不是灰色呢秉扑?最后找到了答案,原來通過代碼設(shè)置的透明和通過主題設(shè)置是有區(qū)別的


image.png
狀態(tài)欄著色
  • 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());
image.png

window.setStatusBarColor(setStatusBarColor());這個(gè)方法設(shè)置狀態(tài)欄的顏色5.x以后才有的api调限,4.4版本需要做特殊處理舟陆。

大家發(fā)現(xiàn)沒有,我一直在6.x的模擬器上設(shè)置了一個(gè)actionBar耻矮,然而這個(gè)actionbar沒有沉浸到狀態(tài)欄下面秦躯,正是如此,我們只能舍棄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>
image.png

toolbar隨著布局頂?shù)綘顟B(tài)欄下面踱承,其實(shí)toolbar有兩種用法:
一種是設(shè)置沒有actionbar的主題(你也可以設(shè)置,但是這樣會(huì)重疊)哨免,將toolbar像上面一樣嵌入布局中茎活,toolbar就是一個(gè)普通的布局,實(shí)質(zhì)上toolbar是繼承的ViewGroup琢唾,這樣沒毛病载荔。
另一種是setSupportActionBar(toolbar),讓toolbar替代actionbar采桃,如果是這樣的話懒熙,主題必須是noActionBar的丘损,不然拋異常,這樣子toolbar就會(huì)繼承actionbar的一些特性工扎,比如設(shè)置透明狀態(tài)欄之后不會(huì)將布局頂上去号俐,而且還為你把toolbar填充了高度。當(dāng)然前提是不能調(diào)用window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);如果調(diào)用了這個(gè)方法定庵,照樣會(huì)頂上去的吏饿,也可以用fitsSystemWindows來配合使用,多嘗試蔬浙。


image.png

就這樣猪落,當(dāng)狀態(tài)欄為透明,toolbar又頂上去了畴博,這樣就顯得整個(gè)主題風(fēng)格一致笨忌,這就是沉浸式。
還有就是app最上端為圖片的時(shí)候希望這樣設(shè)計(jì):


image.png

這叫透明狀態(tài)欄俱病,反正也沒個(gè)規(guī)范的說法官疲,我就這么叫的。

4.4狀態(tài)欄著色

4.4版本唯一一個(gè)和5.x版本不一樣的地方就是4.4沒有改變狀態(tài)欄顏色的api亮隙,只有改變透明度的api途凫,那怎么解決這個(gè)問題呢?
我們都知道溢吻,整個(gè)app展現(xiàn)在我們眼前的最外層的視圖為DecorView维费,實(shí)質(zhì)上是一個(gè)FramLayout,狀態(tài)欄是系統(tǒng)的窗口促王,覆蓋在DecorView之上的犀盟,DecorView里面有我們的content,既然是這樣蝇狼,我們可以在DecorView里面加一個(gè)布局阅畴,覆蓋在content之上,通過設(shè)置狀態(tài)欄透明迅耘,改變這個(gè)View的顏色贱枣,這樣就造成了改變狀態(tài)欄顏色的假象。這些事情早就有人遭了輪子豹障,在這里就不重復(fù)了冯事。
StatusBarUtil

總結(jié):

  • 4.4以上才有沉浸式狀態(tài)欄
  • 設(shè)置狀態(tài)欄透明或者任意顏色(可以通過主題和代碼方法)使得布局頂?shù)綘顟B(tài)欄下面
  • toolbar替換actionbar使得沉浸式得以實(shí)現(xiàn)

下一篇寫toolbar的使用和沉浸式BaseActivity基類的封裝

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市血公,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缓熟,老刑警劉巖累魔,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摔笤,死亡現(xiàn)場離奇詭異,居然都是意外死亡垦写,警方通過查閱死者的電腦和手機(jī)吕世,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梯投,“玉大人命辖,你說我怎么就攤上這事》直停” “怎么了尔艇?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長么鹤。 經(jīng)常有香客問我终娃,道長,這世上最難降的妖魔是什么蒸甜? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任棠耕,我火速辦了婚禮,結(jié)果婚禮上柠新,老公的妹妹穿的比我還像新娘窍荧。我一直安慰自己,他們只是感情好恨憎,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布搅荞。 她就那樣靜靜地躺著,像睡著了一般框咙。 火紅的嫁衣襯著肌膚如雪咕痛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天喇嘱,我揣著相機(jī)與錄音茉贡,去河邊找鬼。 笑死者铜,一個(gè)胖子當(dāng)著我的面吹牛腔丧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播作烟,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼愉粤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拿撩?” 一聲冷哼從身側(cè)響起衣厘,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后影暴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體错邦,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年型宙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撬呢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,769評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妆兑,死狀恐怖魂拦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搁嗓,我是刑警寧澤芯勘,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站谱姓,受9級特大地震影響借尿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屉来,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一路翻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茄靠,春花似錦茂契、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脐雪,卻和暖如春厌小,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背战秋。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工璧亚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脂信。 一個(gè)月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓癣蟋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狰闪。 傳聞我的和親對象是個(gè)殘疾皇子疯搅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容