Android透明狀態(tài)欄與沉浸模式全解

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)記用|連接,這里著重解釋一下這幾個標(biāo)記

  • View.SYSTEM_UI_FLAG_LAYOUT_STABLE Level 16
    保持整個View穩(wěn)定,使View不會因為SystemUI的變化而做layout,常跟statusbar 懸浮, 隱藏共用,若不設(shè)置的話,statusbar的的顯示和隱藏則會導(dǎo)致ContentView重新計算大小并繪制,因此這個標(biāo)記通常是必須的

  • View.SYSTEM_UI_FLAG_FULLSCREEN Level 16
    狀態(tài)欄隱藏,完全不見了,就如同在看視頻時,屏幕上沒有任何內(nèi)容之外的東西

  • View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Level 16
    狀態(tài)欄透明,懸浮在浮于Activity的上面,想像有個z軸,這時activity可以完全占用整個屏幕,而之前我們的屏幕還要分一些給statusbar

  • View.SYSTEM_UI_FLAG_HIDE_NAVIGATION Level 14
    隱藏導(dǎo)航欄, 性質(zhì)如SYSTEM_UI_FLAG_FULLSCREEN

  • View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION Level 16
    導(dǎo)航欄上浮于Activity,性質(zhì)如SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

1.首先看效果圖(1)和(3),這兩個的實現(xiàn)原理其實一樣,就是狀態(tài)欄著色的顏色不同,又兩種實現(xiàn)思路

1.直接將狀態(tài)欄的顏色設(shè)置為目標(biāo)顏色
window.setStatusBarColor(int);

它只適用于5.0之后。因此直接設(shè)置statusBar顏色的方式在5.0以下不行

2.將狀態(tài)欄設(shè)置為"透明+懸浮",這時我們的布局就可以延伸到狀態(tài)欄下面了,然后在activity的布局里面制造一塊和狀態(tài)欄等尺寸的view,設(shè)置需要的背景顏色即可,因為狀態(tài)欄是透明的,因此看起來就像是狀態(tài)欄被上了色一樣,效果相同。通過添加這個標(biāo)記便可以實現(xiàn)我們需要的"透明+懸浮"效果,
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

順變說下清除標(biāo)記的方法
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

其實我們查看FLAG_TRANSLUCENT_STATUS的源碼就會發(fā)現(xiàn),它其實就是上面說的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便不會進入狀態(tài)欄的下方了
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    //設(shè)置狀態(tài)欄顏色
    window.setStatusBarColor(getResources().getColor(R.color.bg_green));
}

/**
 * 思路:設(shè)置狀態(tài)欄懸浮透明,然后制造一個和狀態(tài)欄等尺寸的View設(shè)置好顏色填進去,就好像是狀態(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;
    }

    //制造一個和狀態(tài)欄等尺寸的 View
    mTopView = new View(this);
    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
    mTopView.setBackgroundColor(statusColor);
    //將view添加到第一個位置
    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不同的方案來實現(xiàn),因為WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS這個標(biāo)記在6.0上不是全透明而是半透明的,那么如果要實現(xiàn)效果(1)網(wǎng)易云音樂那樣的效果的話就不行了,所以在5.0以上的版本我們直接設(shè)置statusBar的顏色。5.0以下通過制造一個和statusbar等尺寸的view著色填進去。

最終的效果如下,讓4.4也有了差不多的效果:


而效果(3)就是改了個深色的顏色就行了:


2.看效果圖(4),這就是讓圖片延伸到狀態(tài)欄下,和1一樣的思路,用純xml和純代碼均可實現(xiàn)

  • XML方式實現(xiàn):
    xml方式就是通過為acitivity設(shè)置style的方式實現(xiàn),因為不同的版本需要的配置不同,因我們?yōu)?.4和5.0建立values文件夾和styles文件,并在樣式文件中建立相同名字的樣式,這樣系統(tǒ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并且呢,其實這個問題前面就說過了

window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

<item name="android:windowTranslucentStatus">true</item>
看出來了嗎,對他們倆其實是一個東西,一個是xml實現(xiàn),一個是代碼實現(xiàn)
所以windowTranslucentStatus在6.0上的效果是半透明的。效果是這樣的,

而我們的最終效果:


另外,如果加了DrawerLayout,打開是狀態(tài)欄在5.0以上沒有任何問題,但是在4.4就是是灰色的。需要添加兩行代碼做處理:

    mDrawerLayout.setFitsSystemWindows(true);
    mDrawerLayout.setClipToPadding(false);

setFitsSystemWindows方法的作用是是否為系統(tǒng)默認的裝飾預(yù)留空間
setClipToPadding方法是使得繪制區(qū)域可以延伸到padding區(qū)域

其實這里用了這兩個方法雖然有效,但是我也不知道為什么,有知道朋友請告訴我。

這樣我們就完全使用代碼完美解決了效果(4)。

  • 代碼實現(xiàn):
    主要就是setSystemUiVisibility的運用

    public void onShow() {
    //5.0以上手動設(shè)置statusBar為透明。不能使用getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //因為這在4.4,5.0確實是全透明,但是在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來實現(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);
    }
}

就這么幾行代碼,注意這個全屏是可以支持到4.1的

參考:
Android Activity 全屏方法總結(jié)
Android 系統(tǒng)狀態(tài)欄沉浸式/透明化完整解決方案
Android 狀態(tài)欄全透明策略
Android開發(fā):Translucent System Bar 的最佳實踐

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內(nèi)容