Android沉浸式狀態欄(透明狀態欄)最佳實現
在Android4.4之前,我們的應用沒法改變手機的狀態欄顏色,當我們打開應用時,會出現上圖中左側的畫面,在屏幕的頂部有一條黑色的狀態欄,和應用的風格非常不協調;為了提供更好的界面交互,google在Android4.4以后提供了設置沉浸式狀態欄的方法,對於沉浸式狀態欄這個名字存在爭議,我們不做討論,實際的效果其實就是透明的狀態欄,然后在狀態欄的位置顯示我們自定義的顏色,通常為應用的actionbar的顏色,或者是將應用的整體的一張圖片也占據到狀態欄中,如下圖所示:
由於這種透明的狀態欄是在Android4.4以后才出現的,所以我們需要為4.4以上的版本做適配,方法有兩種,一種是在資源文件(style)中設置,一個是在代碼中設置。
在資源文件中設置透明狀態欄
首先,我們先在values下的style中加入如下代碼:
<!-- Base application theme. --> <style name="AppTheme" 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/colorAccent</item> </style> <style name="AppTheme.Main" parent="AppTheme" />
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
AppTheme.Main是我們要設置給activity的主題,它應該繼承於AppTheme.NoActionBar,然后
我們在values-v19中加入同樣的AppTheme.Main,如下所示:
<style name="AppTheme.Main" parent="AppTheme.NoActionBar"> <item name="android:windowTranslucentStatus">true</item> </style>
- 1
- 2
- 3
然后運行程序,效果如圖所示:
圖片中我們發現,雖然我們實現了透明的狀態欄,但是上邊的文字和狀態欄的信息重疊了。為了修復這個問題,我們應該在布局文件的根布局中加入android:fitsSystemWindows=”true” 就可以了,加入后效果如下:
應用的文字和系統顯示的文字錯開了,這也是我們最終的顯示效果
需要注意的幾點:
- 為Android4.4+適配的同時,不要忘了在values的style.xml中加入同名的自定義style,不然4.4以下會報錯
- 不要忘記在布局文件中加入 android:fitsSystemWindows=”true”,不然布局內容會和狀態欄內容重疊
-
在Android5.0中,透明標題的效果和4.4中有所不同,但是實現方法相同,我們可以不必為5.0+單獨適配,同時5.0+的版本提供了新的API android:statusBarColor,可以用來單獨設置狀態欄的顏色,但是這種方法不適用於我們例子中的圖片占據狀態欄,它適用於純色的狀態欄,並且它應該放到value-v21文件夾中
上邊的例子中,我們只設置了一個圖片,使其占據了狀態欄。但是我們平常見到更多的可能不是這種,而且帶actionbar的情況,如下所示:
在上圖中,存在一個actionbar,然后狀態欄的顏色與其相同,接下來我們來實現這種效果。
style文件不用改變,我們需要在布局文件中加入一個toolbar,代碼如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:background="@color/colorAccent" android:orientation="vertical" tools:context="com.zephyr.musicapp.MainActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/> </LinearLayout> 然后在activity中 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
在一個LinearLayout中包含了一個toolbar,和第一個例子相比,我們把android:fitsSystemWindows=”true”加在了Toolbar上邊,而不是LinearLayout中,如果把android:fitsSystemWindows=”true”放到LinearLayout中,會出現下邊的效果:
雖然狀態欄透明了,但是顏色卻和根布局的顏色相同而不是toolbar,這樣顯然不行,如果我們把android:fitsSystemWindows=”true”放到toolbar中就可以實現我們的效果,如下圖所示:
在這里,我們還需要特別注意一個地方,那就是在設置toolbar高度的時候,應該設置成wrap_content,不然也沒法實現我們的效果,比如我把高度固定為50dp,效果如下:
雖然占據了狀態欄,但是toolbar的高度明顯不夠了,效果很不好。
在Android5.0以后,增加了新的API android:statusBarColor 用於設置狀態欄的顏色,同時以前的windowTranslucentStatus也是對它有效的,所以如果想通過新的API設置狀態欄顏色的話,首先應該將windowTranslucentStatus設置為false,不然是沒有效果的。
以上就是通過資源文件設置透明狀態欄的方法。
代碼中設置透明狀態欄
在代碼中設置透明狀態欄的方法也很簡單,思路就是首先通過 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS設置當前window為透明狀態欄,這樣標題欄就可以占據狀態欄了,但是會出現布局中的內容和狀態欄的內容重疊的問題,為了解決這個問題,我們應該獲得狀態欄的高度,然后設置標題欄的paddingTop為狀態欄的高度,這樣就可以實現透明效果的標題欄的,代碼如下:
protected void setImmerseLayout(View view) {// view為標題欄 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); int statusBarHeight = getStatusBarHeight(this.getBaseContext()); view.setPadding(0, statusBarHeight, 0, 0); } } public int getStatusBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
fitSystemWindows屬性:
官方描述:
Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.
補充:
當為純色actionbar的情況下,我們將toolbar的高度設為wrap_content,並且將fitsSystemWindows=“true”參數設置到了toolbar上,這樣雖然實現了4.4版本的沉浸效果,但是卻不能有效的適配5.0及以上的版本,所以做出以上修改。
在4.4版本上:
1. 我們將根布局的背景顏色設置成和toolbar一樣的,並且設fitsSystemWindows為true。
2. toolbar的fitsSystemWindows屬性去掉,並且高度設置為?attr/actionBarSize
3. 在toolbar下增加一個子布局,顏色設置為white,這樣就可以在4.4及5.0以上實現帶actionbar的沉浸式布局
2017.12.14更新:
使用純色actionbar的時候,可以使用容器包裹toolbar,只設置容器 fitsSystemWindows為true。由於fitsSystemWindows屬性本質上是給當前控件設置了一個padding,所以我們設置到根布局的話,會導致狀態欄是透明的,並且和窗口背景一樣,和toolbar背景不同。如果我們設置給toolbar,則會由於padding的存在,導致toolbar的內容下移。所以我們選擇使用LinearLayout包裹toolbar,並將toolbar的背景等屬性設置在appbarlayout上就可以完美實現效果,代碼:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="Login"/>
</LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13