其實我是不打算寫這篇文章的,爲何呢?由於關於沉浸式狀態欄的文章太多了,隨便google一下就能出來幾十上百篇文章,固然這其中有寫的好的,也有濫竽充數的。前面在公衆號推出了Material Design 的系列文章,就有讀者留言,但願出一篇關於沉浸式的文章。所以這篇文章就整理總結一下各個版本的實現原理,順便爲你們推薦一個我以爲很方便的一個庫。java
在介紹這個方便的輪子以前,咱們先一塊兒來回顧一下實現沉浸式狀態欄的通常套路。在Android上,關於對StatusBar(狀態欄)的操做,一直都在不斷改善,而且表現愈來愈好,在Android4.4 如下,咱們能夠對StatusBar和 NavigationBar進行顯示和隱藏操做。可是直到Android4.4,咱們才能真正意義上的實現沉浸式狀態欄。從Android4.4 到如今(Android 7.1),關於沉浸式大概能夠分紅三個階段:android
Android4.4(API 19) - Android 5.0(API 21): 這個階段能夠實現沉浸式,可是表現得還不是很好,實現方式爲: 經過FLAG_TRANSLUCENT_STATUS
設置狀態欄爲透明而且爲全屏模式,而後經過添加一個與StatusBar 同樣大小的View,將View 的 background 設置爲咱們想要的顏色,從而來實現沉浸式。git
Android 5.0(API 21)以上版本: 在Android 5.0的時候,加入了一個重要的屬性和方法 android:statusBarColor
(對應方法爲 setStatusBarColor),經過這個方法咱們就能夠輕鬆實現沉浸式。也就是說,從Android5.0開始,系統才真正的支持沉浸式。github
Android 6.0(API 23)以上版本:其實Android6.0以上的實現方式和Android 5.0 +是同樣,爲何要將它歸爲一個單獨重要的階段呢?是由於從Android 6.0(API 23)開始,咱們能夠改狀態欄的繪製模式,能夠顯示白色或淺黑色的內容和圖標(除了魅族手機,魅族自家有作源碼更改,6.0如下就能實現)ide
大概就是這個三個階段,那麼接下來咱們就看一下這個三個階段分別是如何來實現的。工具
2.1 Android4.4(API 19) - Android 5.0(API 21)實現沉浸式的方式佈局
Android 4.4 爲何可以實現沉浸式的效果呢?由於在Android 4.4 新增了一個重要的屬性:FLAG_TRANSLUCENT_STATUS
ui
/** * Window flag: request a translucent status bar with minimal system-provided * background protection. * * <p>This flag can be controlled in your theme through the * {@link android.R.attr#windowTranslucentStatus} attribute; this attribute * is automatically set for you in the standard translucent decor themes * such as * {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor}, * {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor}, * {@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.</p> * * <p>When this flag is enabled for a window, it automatically sets * the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.</p> */
public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;複製代碼
解釋:設置狀態欄透明,而且變爲全屏模式。上面的解釋已經說得很清楚了,當window的這個屬性有效的時候,會自動設置 system ui visibility的標誌
SYSTEM_UI_FLAG_LAYOUT_STABLE
和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
。this
有兩種方式實現這個屬性:google
能夠在代碼中設置,以下:
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);複製代碼
固然也能夠在theme 中設置屬性windowTranslucentStatus
,以下:
android:windowTranslucentStatus複製代碼
效果以下:
效果如上圖,能夠看出,沉浸式的效果是出來了,可是也有一個問題,咱們的標題欄和狀態欄重疊了,至關於整個佈局上移了StatusBar 的高度。
爲了讓標題欄回到原來的位置,咱們在標題欄的上方添加一個大小和StatusBar大小同樣的View,View 的BackgroundColor 爲標題欄同樣的顏色,這個View起到一個佔位的做用。這個時候,標題欄就會下移StatusBar的高度,回到正常的位置。
添加以下代碼:
//獲取windowphone下的decorView
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
int count = decorView.getChildCount();
//判斷是否已經添加了statusBarView
if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
} else {
//新建一個和狀態欄高寬的view
StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
decorView.addView(statusView);
}
ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
//rootview不會爲狀態欄留出狀態欄空間
ViewCompat.setFitsSystemWindows(rootView,true);
rootView.setClipToPadding(true);複製代碼
建立和status bar 同樣大小的View的代碼以下:
private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) {
// 繪製一個和狀態欄同樣高的矩形
StatusBarView statusBarView = new StatusBarView(activity);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
statusBarView.setLayoutParams(params);
statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
return statusBarView;
}複製代碼
其中StatusBarView 就是一個普通的View。
添加上述代碼後,效果以下:
經過以上就能夠實現Android 4.4 上的沉浸式狀態欄。
另外,若是是一張圖片延伸到狀態欄的話,直接設置FLAG_TRANSLUCENT_STATUS
就能夠了,以下:
小結:Android4.4上實現沉浸式狀態欄的套路是:爲window添加
FLAG_TRANSLUCENT_STATUS
Flag,而後添加一個和status bar 同樣大小的View 站位,從而讓讓標題欄不會與status bar 重疊。而圖片延伸到狀態欄只須要設置FLAG_TRANSLUCENT_STATUS
就OK。
前面說過,沉浸式在Android4.4 - Android5.0 之間的版本表現得不是很好,從上面貼的幾張圖就能夠看出,狀態欄的頂部有一個漸變,會顯示出黑色的陰影(底部的導航欄也是同樣的效果),在Android 5.0 版本已經被修復了。
2.2 Android 5.0(API 21)以上實現沉浸式的方式
Android 5.0 是一個里程碑式的版本,從Android 5.0開始,Google 推出了全新的設計規範 Material Design,而且原生控件就能夠實現一些炫酷的UI動效。從這個版本開始,google 加入了一個比較重要的方法setStatusBarColor
(對應屬性:android:statusBarColor
),經過這個方法,能夠很輕鬆地實現沉浸式狀態欄。方法以下:
/** * Sets the color of the status bar to {@code color}. * * For this to take effect, * the window must be drawing the system bar backgrounds with * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set. * * If {@code color} is not opaque, consider setting * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}. * <p> * The transitionName for the view background will be "android:status:background". * </p> */
public abstract void setStatusBarColor(@ColorInt int color);複製代碼
注意看這個方法的註釋,想要這個方法生效,必須還要配合一個Flag一塊兒使用,必須設置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
,而且不能設置FLAG_TRANSLUCENT_STATUS
(Android 4.4才用這個)
咱們來看一下FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
這個flag:
能夠看到,這個flag 也是在Android 5.0添加的,它的做用是什麼呢?
解釋:設置了
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
,代表會Window負責系統bar的background 繪製,繪製透明背景的系統bar(狀態欄和導航欄),而後用getStatusBarColor()
和getNavigationBarColor()
的顏色填充相應的區域。這就是Android 5.0 以上實現沉浸式導航欄的原理。
實現沉浸式添加以下代碼:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//注意要清除 FLAG_TRANSLUCENT_STATUS flag
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));複製代碼
效果以下:
固然也能夠直接在Theme中使用,在values-v21文件夾下添加以下主題:
<style name="MDTheme" parent="Theme.Design.Light.NoActionBar">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/holo_red_light</item>
</style>複製代碼
效果和上面代碼中添加的效果同樣,這裏就不貼效果圖了。
圖片延伸到狀態欄
在Android 5.0 使圖片延伸到狀態欄,只需設置windowTranslucentStatus
,將 statusBarColor 設置爲透明便可:
<style name="ImageTranslucentTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowTranslucentStatus">true</item>
<!-- 設置statusBarColor 爲透明-->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>複製代碼
效果以下:
代碼中經過版本號的判斷兼容 Android5.0如下和Android 5.0以上:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
int count = decorView.getChildCount();
if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
} else {
StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
decorView.addView(statusView);
}
ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
rootView.setFitsSystemWindows(true);
rootView.setClipToPadding(true);
setRootView(activity);
}複製代碼
2.3 Android 6.0 + 實現狀態欄字色和圖標淺黑色
使用沉浸式的時候會遇到一個問題,那就是Android 系統狀態欄的字色和圖標顏色爲白色,當個人主題色或者圖片接近白色或者爲淺色的時候,狀態欄上的內容就看不清了。 ,這個問題在Android 6.0的時候獲得瞭解決。Android 6.0 新添加了一個屬性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
解釋:爲setSystemUiVisibility(int)方法添加的Flag,請求status bar 繪製模式,它能夠兼容亮色背景的status bar 。要在設置了
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
flag ,同時清除了FLAG_TRANSLUCENT_STATUS
flag 纔會生效。
添加以下代碼:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}複製代碼
效果以下:
除了在代碼中添加之外,還能夠直接在主題中使用屬性:
<style name="MDTheme" parent="Theme.Design.Light.NoActionBar">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/holo_red_light</item>
<!-- Android 6.0以上 狀態欄字色和圖標爲淺黑色-->
<item name="android:windowLightStatusBar">true</item>
</style>複製代碼
注意:主題要放在values-v23文件夾下:
經過上面的介紹,其實將各個版本實現沉浸式的方式和原理都講完了。可是或許當你真正去實踐沉浸式狀態欄的時候,你會感受到無從下手,所以,我給你們推薦一個輪子StatusBarUtil,Github:github.com/laobie/Stat…。
爲何會推薦這個庫呢?由於這個庫就只有一個類StatusBarUtil
,使用起來很方便,就像一個工具類同樣使用。裏面封裝了不少靜態方法,直接使用就好。本身添加也很方便。介紹一下使用的一些場景:
須要在setContentView()
以後調用:
setContentView(R.layout.main_activity);
...
StatusBarUtil.setColor(MainActivity.this, mColor);複製代碼
StatusBarUtil.setColor(Activity activity, int color)複製代碼
StatusBarUtil.setTranslucent(Activity activity, int statusBarAlpha)複製代碼
StatusBarUtil.setTransparent(Activity activity)複製代碼
StatusBarUtil.setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color)複製代碼
StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView)複製代碼
以上就是對於沉浸式狀態欄的一些總結,但願能夠給尚未使用沉浸式的同窗一些幫助。若是你已經使用過沉浸式狀態欄,也不仿看一下,能夠對各個版本實現的原理有一個更深的瞭解。最後,推薦了一個不錯的庫,更確切的說,應該是一個不錯的工具類。若有問題,歡迎交流。
更多Android乾貨文章,關注公衆號【Android技術雜貨鋪】