Android透明狀態(tài)欄與沉浸模式全解
現(xiàn)在如今利用狀態(tài)欄做文章的主要就是如下四種場景了,先上圖
- 網(wǎng)易云音樂 狀態(tài)欄與標(biāo)題欄同色呻征,無縫銜接
- 多看閱讀 全屏沉浸閱讀(視頻谆级,游戲同理)
- 淘寶 狀態(tài)欄深色
- 餓了么 圖片延伸至狀態(tài)欄下面
透明狀態(tài)欄模式就是大家說的"沉浸式狀態(tài)欄"了.
沉浸模式是一般用于小說洞拨、視頻扯罐、游戲。將用戶的注意完全聚焦在內(nèi)容上烦衣,是真正的沉浸模式.
從3.x版本開始, 系統(tǒng)DecorView提供了setSystemUiVisibility方法, 可以通過設(shè)置Flag更改所謂SystemUI的屬性歹河,可以操作各種狀態(tài)欄掩浙,導(dǎo)航欄的的顯示與隱藏效果。非常好用秸歧,有篇很好的總結(jié)文章Android Activity 全屏方法總結(jié)
調(diào)用方式:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
);
不同的標(biāo)記用|連接厨姚,這里著重解釋一下這幾個(gè)標(biāo)記
View.SYSTEM_UI_FLAG_LAYOUT_STABLE Level 16
保持整個(gè)View穩(wěn)定,使View不會(huì)因?yàn)镾ystemUI的變化而做layout,常跟statusbar 懸浮, 隱藏共用,若不設(shè)置的話键菱,statusbar的的顯示和隱藏則會(huì)導(dǎo)致ContentView重新計(jì)算大小并繪制谬墙,因此這個(gè)標(biāo)記通常是必須的View.SYSTEM_UI_FLAG_FULLSCREEN Level 16
狀態(tài)欄隱藏,完全不見了经备,就如同在看視頻時(shí)拭抬,屏幕上沒有任何內(nèi)容之外的東西View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Level 16
狀態(tài)欄透明,懸浮在浮于Activity的上面侵蒙,想像有個(gè)z軸造虎,這時(shí)activity可以完全占用整個(gè)屏幕,而之前我們的屏幕還要分一些給statusbarView.SYSTEM_UI_FLAG_HIDE_NAVIGATION Level 14
隱藏導(dǎo)航欄, 性質(zhì)如SYSTEM_UI_FLAG_FULLSCREENView.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION Level 16
導(dǎo)航欄上浮于Activity纷闺,性質(zhì)如SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
1.首先看效果圖(1)和(3)算凿,這兩個(gè)的實(shí)現(xiàn)原理其實(shí)一樣,就是狀態(tài)欄著色的顏色不同犁功,又兩種實(shí)現(xiàn)思路
1.直接將狀態(tài)欄的顏色設(shè)置為目標(biāo)顏色
window.setStatusBarColor(int);
它只適用于5.0之后氓轰。因此直接設(shè)置statusBar顏色的方式在5.0以下不行
2.將狀態(tài)欄設(shè)置為"透明+懸浮",這時(shí)我們的布局就可以延伸到狀態(tài)欄下面了波桩,然后在activity的布局里面制造一塊和狀態(tài)欄等尺寸的view,設(shè)置需要的背景顏色即可请敦,因?yàn)闋顟B(tài)欄是透明的镐躲,因此看起來就像是狀態(tài)欄被上了色一樣,效果相同侍筛。通過添加這個(gè)標(biāo)記便可以實(shí)現(xiàn)我們需要的"透明+懸浮"效果萤皂,
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
順變說下清除標(biāo)記的方法
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
其實(shí)我們查看FLAG_TRANSLUCENT_STATUS的源碼就會(huì)發(fā)現(xiàn),它其實(shí)就是上面說的system UI visibility flags里面的穩(wěn)定布局SYSTEM_UI_FLAG_LAYOUT_STABLE和懸浮status標(biāo)記的組合
* <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;
這就很容易理解了匣椰,現(xiàn)在直接上全部代碼
/**
* 思路:直接設(shè)置狀態(tài)欄的顏色
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setStatusBarUpperAPI21() {
Window window = getWindow();
//取消設(shè)置懸浮透明狀態(tài)欄,ContentView便不會(huì)進(jìn)入狀態(tài)欄的下方了
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//設(shè)置狀態(tài)欄顏色
window.setStatusBarColor(getResources().getColor(R.color.bg_green));
}
/**
* 思路:設(shè)置狀態(tài)欄懸浮透明裆熙,然后制造一個(gè)和狀態(tài)欄等尺寸的View設(shè)置好顏色填進(jìn)去,就好像是狀態(tài)欄著色了一樣
*/
private void setStatusBarUpperAPI19() {
Window window = getWindow();
//設(shè)置懸浮透明狀態(tài)欄
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup mContentView = (ViewGroup) findViewById(Window.ID_ANDROID_CONTENT);
int statusBarHeight = getStatusBarHeight();
int statusColor = getResources().getColor(R.color.bg_green);
View mTopView = mContentView.getChildAt(0);
if (mTopView != null && mTopView.getLayoutParams() != null &&
mTopView.getLayoutParams().height == statusBarHeight) {
mTopView.setBackgroundColor(statusColor);
return;
}
//制造一個(gè)和狀態(tài)欄等尺寸的 View
mTopView = new View(this);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
mTopView.setBackgroundColor(statusColor);
//將view添加到第一個(gè)位置
mContentView.addView(mTopView, 0, lp);
}
private int getStatusBarHeight() {
int result = 0;
int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resId > 0) {
result = getResources().getDimensionPixelSize(resId);
}
return result;
}
這里注意為什么還要區(qū)分5.0和4.4不同的方案來實(shí)現(xiàn)禽笑,因?yàn)閃indowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS這個(gè)標(biāo)記在6.0上不是全透明而是半透明的入录,那么如果要實(shí)現(xiàn)效果(1)網(wǎng)易云音樂那樣的效果的話就不行了,所以在5.0以上的版本我們直接設(shè)置statusBar的顏色佳镜。5.0以下通過制造一個(gè)和statusbar等尺寸的view著色填進(jìn)去僚稿。
最終的效果如下,讓4.4也有了差不多的效果:
而效果(3)就是改了個(gè)深色的顏色就行了:
2.看效果圖(4)蟀伸,這就是讓圖片延伸到狀態(tài)欄下蚀同,和1一樣的思路缅刽,用純xml和純代碼均可實(shí)現(xiàn)
- XML方式實(shí)現(xiàn):
xml方式就是通過為acitivity設(shè)置style的方式實(shí)現(xiàn),因?yàn)椴煌陌姹拘枰呐渲貌煌缆纾蛭覀優(yōu)?.4和5.0建立values文件夾和styles文件衰猛,并在樣式文件中建立相同名字的樣式,這樣系統(tǒng)就能判斷手機(jī)版本自動(dòng)使用對應(yīng)版本values文件夾下的樣式刹孔,如圖所示啡省,注意路徑
values/styles.xml添加內(nèi)容:
<style name="fullScreenTheme" parent="AppTheme">
</style>
values-v19/styles.xml添加內(nèi)容:
<style name="fullScreenTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
values-v21/styles.xml添加內(nèi)容:
<style name="fullScreenTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
windowTranslucentStatus:設(shè)置透明懸浮狀態(tài)欄,4.4就有
windowTranslucentNavigation:設(shè)置透明懸浮導(dǎo)航欄芦疏,4.4就有
注意既然windowTranslucentStatus在4.4就有了冕杠,為什么在5.0的style要設(shè)置windowTranslucentStatus為false并且呢,其實(shí)這個(gè)問題前面就說過了
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
和
<item name="android:windowTranslucentStatus">true</item>
看出來了嗎酸茴,對他們倆其實(shí)是一個(gè)東西分预,一個(gè)是xml實(shí)現(xiàn),一個(gè)是代碼實(shí)現(xiàn)
所以windowTranslucentStatus在6.0上的效果是半透明的薪捍。效果是這樣的笼痹,
而我們的最終效果:
另外,如果加了DrawerLayout酪穿,打開是狀態(tài)欄在5.0以上沒有任何問題凳干,但是在4.4就是是灰色的。需要添加兩行代碼做處理:
mDrawerLayout.setFitsSystemWindows(true);
mDrawerLayout.setClipToPadding(false);
setFitsSystemWindows方法的作用是是否為系統(tǒng)默認(rèn)的裝飾預(yù)留空間
setClipToPadding方法是使得繪制區(qū)域可以延伸到padding區(qū)域
其實(shí)這里用了這兩個(gè)方法雖然有效被济,但是我也不知道為什么救赐,有知道朋友請告訴我。
這樣我們就完全使用代碼完美解決了效果(4)只磷。
-
代碼實(shí)現(xiàn):
主要就是setSystemUiVisibility的運(yùn)用public void onShow() {
//5.0以上手動(dòng)設(shè)置statusBar為透明经磅。不能使用getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//因?yàn)檫@在4.4,5.0確實(shí)是全透明,但是在6.0是半透明!!!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION );
}
3.效果(2)全屏沉浸钮追,如小說预厌,視頻,游戲
在看完setSystemUiVisibility的各種flag的左右后元媚,應(yīng)該可以憑自己的需要組合搭配flag來實(shí)現(xiàn)全屏了轧叽,直接上代碼:
public void onHide() {
//4.1及以上通用flags組合
int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().getDecorView().setSystemUiVisibility(
flags | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getWindow().getDecorView().setSystemUiVisibility(flags);
}
}
就這么幾行代碼,注意這個(gè)全屏是可以支持到4.1的
參考:
Android Activity 全屏方法總結(jié)
Android 系統(tǒng)狀態(tài)欄沉浸式/透明化完整解決方案
Android 狀態(tài)欄全透明策略
Android開發(fā):Translucent System Bar 的最佳實(shí)踐