網上談論“沉浸式”的文章多的不可勝數寿酌,有人把“沉浸式”叫做“沉浸式狀態(tài)欄”,還有人稱作為“透明狀態(tài)欄”、“變色狀態(tài)欄”等低千。
這里我們先給出“沉浸式”的直觀感受,引用“知乎”網友的答案
使用帶虛擬鍵的手機才能明顯感覺到沉浸式所帶來的變化:狀態(tài)欄、導航欄隱藏示血。
而對于使用實體按鍵的手機的用戶來說棋傍,“沉浸式”所帶來的變化僅僅是狀態(tài)欄隱藏,事實上难审,狀態(tài)欄隱藏在之前也很常見瘫拣,各種國產應用啟動時都會隱藏狀態(tài)欄。
出處來自:為什么在國內會有很多用戶把 ?透明欄?(Translucent Bars)稱作 ?沉浸式頂欄?告喊?感興趣的朋友可以去閱讀下麸拄。
把上面的文字翻譯成圖片的話,標準的“沉浸式”大致是這個效果黔姜。
App默認是全屏的拢切,用戶可以從頂部或者底部“滑出”狀態(tài)欄和導航欄,一段時間后狀態(tài)欄和導航欄會自動消失秆吵。
嗯淮椰,沒錯,這個才是標準的“沉浸式”纳寂。
有了以上的定義主穗,下面這兩種常見的效果,只能說改變了狀態(tài)欄的“樣式”(Translucent Bar倒是比較貼近)毙芜。但是黔牵,他們不是“沉浸式”。
接下來爷肝,將進入本篇文章的主題猾浦,我們會從兩個方面去“論沉浸式”。
- 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_LAYOUT_FULLSCREEN(4.1+):配合SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN一起使用通殃,效果使得狀態(tài)欄出現的時候不會擠壓activity高度度液,狀態(tài)欄會覆蓋在activity之上。
- SYSTEM_UI_FLAG_HIDE_NAVIGATION(4.0+)
:會使得虛擬導航欄隱藏,但同樣用戶可以從屏幕下邊緣“拖出”且不會再次消失堕担,同時activity界面會被擠壓已慢。
- SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION(4.1+):配合 SYSTEM_UI_FLAG_HIDE_NAVIGATION 一起使用,效果使得導航欄出現的時候不會擠壓activity高度霹购,導航欄會覆蓋在activity之上佑惠。
- SYSTEM_UI_FLAG_LAYOUT_STABLE(4.1+):使用以上四個屬性,可以達到activity占據屏幕所有空間齐疙,同時狀態(tài)欄和導航欄可以懸浮在activity之上的效果兢仰。但是此時activity的內容也會(比如頂部和底部各有一個TextView)狀態(tài)欄和導航欄之下,當狀態(tài)欄和導航欄出現的時候剂碴,看起來會這樣:
顯然,文字被遮蓋了我們是不能接受的轻专,此時我們需要另外一個屬性忆矛,android:fitsSystemWindows=“true”
,這個屬性表示系統(tǒng)UI(狀態(tài)欄请垛、導航欄)可見的時候催训,會給我們的布局加上padding(paddingTop、paddingBottom)屬性宗收,這樣內容就不會被蓋住了漫拭。我們在activity的根布局加上這個屬性,效果如下
我們發(fā)現混稽,當狀態(tài)欄和導航欄出現的時候采驻,內容會被擠壓一下,這個體驗也不是很理想匈勋,那么怎么解決這個問題呢礼旅?
其實,我們的內容本就不該占據狀態(tài)欄和導航欄的位置(游戲一般才會全屏洽洁,普通app的狀態(tài)欄一般都是透明而不是讓內容去占據這個空間痘系,后面會介紹怎么實現狀態(tài)欄“透明效果”),我們需要加上SYSTEM_UI_FLAG_LAYOUT_STABLE這個屬性來解決這個問題
饿自,效果如下
以上都是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一起使用,會帶來一個全新的“全屏沉浸模式”雳旅。我們使用這兩個屬性看下效果~
納尼跟磨?顯然和官方描述的占據整個屏幕有點不符合,狀態(tài)欄一直占據著空間(不知道為何官方這么描述~)攒盈。我們再加一個屬性SYSTEM_UI_FLAG_FULLSCREEN抵拘,我們再來看下效果
擠壓的效果如果你不滿意,加上SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION型豁,這會讓狀態(tài)欄和導航欄“懸浮”在activity之上僵蛛,這個前面提到過,不做更多解釋迎变,效果如下
- SYSTEM_UI_FLAG_IMMERSIVE_STICKY:和SYSTEM_UI_FLAG_IMMERSIVE相似充尉,它被稱作“粘性”的沉浸模式,這個模式會在狀態(tài)欄和導航欄顯示一段時間后衣形,自動隱藏(你可以點擊一下屏幕驼侠,立即隱藏)。同時需要重點說明的是谆吴,這種模式下倒源,狀態(tài)欄和導航欄出現的時候是“半透明”狀態(tài),效果如下
我覺得官方要表達的“Immersive full-screen mode”句狼,應該是這個意思才對吧笋熬?
慎用“沉浸式”,除非你真的需要這樣做腻菇。比如做一款游戲或者繪圖應用就很合適胳螟。
“Translucent Bar”
網上所謂的“沉浸式狀態(tài)欄”,這個概念官方從未提及過筹吐。我看了就大多數文章旺隙,最終表達的效果基本是這樣
為了對比,貼出了不同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>
有些應用沒有標題,希望將背景和標題融為一體桩警,比如頂部是“輪播”欄:
其實也很簡單可训,布局稍微調整下(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也沒有特意去做處理术瓮,我也覺得沒必要,你覺得呢贰健?
好了胞四,希望本文能幫助你真正理解什么是“沉浸式”。