刨根問底-論Android“沉浸式”

網上談論“沉浸式”的文章多的不可勝數寿酌,有人把“沉浸式”叫做“沉浸式狀態(tài)欄”,還有人稱作為“透明狀態(tài)欄”“變色狀態(tài)欄”等低千。

這里我們先給出“沉浸式”的直觀感受,引用“知乎”網友的答案

使用帶虛擬鍵的手機才能明顯感覺到沉浸式所帶來的變化:狀態(tài)欄、導航欄隱藏示血。
而對于使用實體按鍵的手機的用戶來說棋傍,“沉浸式”所帶來的變化僅僅是狀態(tài)欄隱藏,事實上难审,狀態(tài)欄隱藏在之前也很常見瘫拣,各種國產應用啟動時都會隱藏狀態(tài)欄。

出處來自:為什么在國內會有很多用戶把 ?透明欄?(Translucent Bars)稱作 ?沉浸式頂欄?告喊?感興趣的朋友可以去閱讀下麸拄。

把上面的文字翻譯成圖片的話,標準的“沉浸式”大致是這個效果黔姜。

標準沉浸式.gif

App默認是全屏的拢切,用戶可以從頂部或者底部“滑出”狀態(tài)欄和導航欄,一段時間后狀態(tài)欄和導航欄會自動消失秆吵。

嗯淮椰,沒錯,這個才是標準的“沉浸式”纳寂。

有了以上的定義主穗,下面這兩種常見的效果,只能說改變了狀態(tài)欄的“樣式”(Translucent Bar倒是比較貼近)毙芜。但是黔牵,他們不是“沉浸式”

非沉浸式.png

接下來爷肝,將進入本篇文章的主題猾浦,我們會從兩個方面去“論沉浸式”

  • 4.4之前灯抛,谷歌是如何提供類似“沉浸式”的體驗的
  • 如何以最簡單的方式實現“狀態(tài)欄”與App“合二為一”的效果(真?zhèn)€真的不叫沉浸式啦~)

setSystemUiVisibility
4.0之后(3.0也支持金赦,這里暫時只討論手機平臺),官方提供了這個方法对嚼,可以改變系統(tǒng)UI的可見性夹抗,使用方法如下:

int flag = View.SYSTEM_UI_FLAG_FULLSCREEN;
getWindow().getDecorView().setSystemUiVisibility(flag);

多個值可使用“|”操作符,比如:

int flag = View.SYSTEM_UI_FLAG_FULLSCREEN 
           | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
getWindow().getDecorView().setSystemUiVisibility(flag);

系統(tǒng)提供了很多類似View.SYSTEM_UI_FLAG_xxx的常量纵竖,具體有下面幾種:

  • SYSTEM_UI_FLAG_FULLSCREEN(4.1+):隱藏狀態(tài)欄漠烧,手指在屏幕頂部往下拖動,狀態(tài)欄會再次出現且不會消失靡砌,另外activity界面會重新調整大小已脓,直觀感覺就是activity高度有個變小的過程。
SYSTEM_UI_FLAG_FULLSCREEN.gif
  • SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN(4.1+):配合SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN一起使用通殃,效果使得狀態(tài)欄出現的時候不會擠壓activity高度度液,狀態(tài)欄會覆蓋在activity之上。
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.gif
  • SYSTEM_UI_FLAG_HIDE_NAVIGATION(4.0+)
    :會使得虛擬導航欄隱藏,但同樣用戶可以從屏幕下邊緣“拖出”且不會再次消失堕担,同時activity界面會被擠壓已慢。
SYSTEM_UI_FLAG_HIDE_NAVIGATION.gif
  • SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION(4.1+):配合 SYSTEM_UI_FLAG_HIDE_NAVIGATION 一起使用,效果使得導航欄出現的時候不會擠壓activity高度霹购,導航欄會覆蓋在activity之上佑惠。
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION.gif
  • SYSTEM_UI_FLAG_LAYOUT_STABLE(4.1+):使用以上四個屬性,可以達到activity占據屏幕所有空間齐疙,同時狀態(tài)欄和導航欄可以懸浮在activity之上的效果兢仰。但是此時activity的內容也會(比如頂部和底部各有一個TextView)狀態(tài)欄和導航欄之下,當狀態(tài)欄和導航欄出現的時候剂碴,看起來會這樣:
1.gif

顯然,文字被遮蓋了我們是不能接受的轻专,此時我們需要另外一個屬性忆矛,android:fitsSystemWindows=“true”,這個屬性表示系統(tǒng)UI(狀態(tài)欄请垛、導航欄)可見的時候催训,會給我們的布局加上padding(paddingTop、paddingBottom)屬性宗收,這樣內容就不會被蓋住了漫拭。我們在activity的根布局加上這個屬性,效果如下

fitsSystemWindows.gif

我們發(fā)現混稽,當狀態(tài)欄和導航欄出現的時候采驻,內容會被擠壓一下,這個體驗也不是很理想匈勋,那么怎么解決這個問題呢礼旅?

其實,我們的內容本就不該占據狀態(tài)欄和導航欄的位置(游戲一般才會全屏洽洁,普通app的狀態(tài)欄一般都是透明而不是讓內容去占據這個空間痘系,后面會介紹怎么實現狀態(tài)欄“透明效果”),我們需要加上SYSTEM_UI_FLAG_LAYOUT_STABLE這個屬性來解決這個問題
饿自,效果如下

SYSTEM_UI_FLAG_LAYOUT_STABLE.gif

以上都是4.1(除了SYSTEM_UI_FLAG_HIDE_NAVIGATION
)的屬性汰翠,觀察之后我們發(fā)現,不管是那種屬性昭雌,狀態(tài)欄和導航欄總是會“遮擋”activity复唤,為了解決這個問題,4.4引入了“全屏沉浸模式”這個概念烛卧。

  • SYSTEM_UI_FLAG_IMMERSIVE(4.4+):這個屬性是用來實現“沉浸式”效果的苟穆,官方稱作“Immersive full-screen mode”

To provide your app with a layout that fills the entire screen, the new SYSTEM_UI_FLAG_IMMERSIVE
flag for setSystemUiVisibility()
(when combined with SYSTEM_UI_FLAG_HIDE_NAVIGATION
) enables a new immersive full-screen mode.

大意是SYSTEM_UI_FLAG_IMMERSIVE和 SYSTEM_UI_FLAG_HIDE_NAVIGATION一起使用,會帶來一個全新的“全屏沉浸模式”雳旅。我們使用這兩個屬性看下效果~

immersive1.gif

納尼跟磨?顯然和官方描述的占據整個屏幕有點不符合,狀態(tài)欄一直占據著空間(不知道為何官方這么描述~)攒盈。我們再加一個屬性SYSTEM_UI_FLAG_FULLSCREEN抵拘,我們再來看下效果

immersive2.gif

擠壓的效果如果你不滿意,加上SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION型豁,這會讓狀態(tài)欄和導航欄“懸浮”在activity之上僵蛛,這個前面提到過,不做更多解釋迎变,效果如下

immersive3.gif
  • SYSTEM_UI_FLAG_IMMERSIVE_STICKY:和SYSTEM_UI_FLAG_IMMERSIVE相似充尉,它被稱作“粘性”的沉浸模式,這個模式會在狀態(tài)欄和導航欄顯示一段時間后衣形,自動隱藏(你可以點擊一下屏幕驼侠,立即隱藏)。同時需要重點說明的是谆吴,這種模式下倒源,狀態(tài)欄和導航欄出現的時候是“半透明”狀態(tài),效果如下
immersive4.gif

我覺得官方要表達的“Immersive full-screen mode”句狼,應該是這個意思才對吧笋熬?

慎用“沉浸式”,除非你真的需要這樣做腻菇。比如做一款游戲或者繪圖應用就很合適胳螟。

“Translucent Bar”
網上所謂的“沉浸式狀態(tài)欄”,這個概念官方從未提及過筹吐。我看了就大多數文章旺隙,最終表達的效果基本是這樣

預覽.png

為了對比,貼出了不同Android版本的效果(某Q也是如此)骏令,其實就是為了讓狀態(tài)欄看上起和我們應用的標題欄(當然蔬捷,也可能是和整個背景)“合二為一”,不至于和之前一樣榔袋,看到的是“黑乎乎”的狀態(tài)欄周拐,網上也有很多第三方庫來實現這樣的效果,比如:SystemBarTint凰兑。

其實這個效果4.4以上實現很簡單妥粟,大概需要用到以下兩個屬性:

  • windowTranslucentStatus:application的主題加上這個屬性,表示狀態(tài)欄半透明吏够,另外勾给,會使得狀態(tài)欄會懸浮在activity之上(此時滩报,activity布局會擴展到狀態(tài)欄底部(Z軸方向)):

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">                                
        <item name="android:windowTranslucentStatus">true</item>
    </style>
    

為了不遮擋activity內容,需要配合另外一個屬性

  • android:fitsSystemWindows:使用這個屬性的View播急,系統(tǒng)會在View頂部添加padding(大小為狀態(tài)欄高度):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true"
            android:background="@color/colorPrimary">
            <!--嵌套的原因是因為LinearLayout會被加上paddingTop脓钾,導致TextView無法居中-->
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="50dp">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:textColor="@android:color/white"
                    android:textSize="20sp"
                    android:text="這是標題"/>
            </RelativeLayout>
        </LinearLayout>
    </LinearLayout>
    

有些應用沒有標題,希望將背景和標題融為一體桩警,比如頂部是“輪播”欄:

預覽2.png

其實也很簡單可训,布局稍微調整下(android:fitsSystemWindows="true"不需要設置。如果你是對一個ViewGroup設置背景捶枢,你可能會用到這個屬性握截,因為你不想ViewGroup的子布局被狀態(tài)欄“遮蓋”):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:scaleType="centerCrop"
        android:src="@drawable/bg"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="內容區(qū)域"/>
</LinearLayout>

總之一個原則是,如果使用以下屬性烂叔,activity布局會擴展到狀態(tài)欄

<item name="android:windowTranslucentStatus">true</item>

如果你希望擴展的區(qū)域谨胞,不被狀態(tài)欄蓋住內容,那就加上

android:fitsSystemWindows="true"

我們注意到蒜鸡,狀態(tài)欄在4.4-5.0之間的效果是全透明胯努,5.0+是半透明,顏色的差別QQ等App也沒有特意去做處理术瓮,我也覺得沒必要,你覺得呢贰健?

好了胞四,希望本文能幫助你真正理解什么是“沉浸式”

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末伶椿,一起剝皮案震驚了整個濱河市辜伟,隨后出現的幾起案子,更是在濱河造成了極大的恐慌脊另,老刑警劉巖导狡,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異偎痛,居然都是意外死亡旱捧,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門踩麦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枚赡,“玉大人,你說我怎么就攤上這事谓谦∑冻龋” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵反粥,是天一觀的道長卢肃。 經常有香客問我疲迂,道長,這世上最難降的妖魔是什么莫湘? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任尤蒿,我火速辦了婚禮,結果婚禮上逊脯,老公的妹妹穿的比我還像新娘优质。我一直安慰自己,他們只是感情好军洼,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布巩螃。 她就那樣靜靜地躺著,像睡著了一般匕争。 火紅的嫁衣襯著肌膚如雪避乏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天甘桑,我揣著相機與錄音拍皮,去河邊找鬼。 笑死跑杭,一個胖子當著我的面吹牛铆帽,可吹牛的內容都是我干的。 我是一名探鬼主播德谅,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼爹橱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窄做?” 一聲冷哼從身側響起愧驱,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椭盏,沒想到半個月后组砚,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡掏颊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年糟红,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乌叶。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡改化,死狀恐怖,靈堂內的尸體忽然破棺而出枉昏,到底是詐尸還是另有隱情陈肛,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布兄裂,位于F島的核電站句旱,受9級特大地震影響阳藻,放射性物質發(fā)生泄漏。R本人自食惡果不足惜谈撒,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一腥泥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啃匿,春花似錦蛔外、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至裆悄,卻和暖如春矛纹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背光稼。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工或南, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艾君。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓采够,卻偏偏與公主長得像,于是被迫代替她去往敵國和親冰垄。 傳聞我的和親對象是個殘疾皇子蹬癌,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容