Android關于沉浸式狀態(tài)欄的一些總結

封面.png

一涝滴、前言

其實我是不打算寫這篇文章的涮瞻,為什么呢鲤拿?因為關于沉浸式狀態(tài)欄的文章太多了,隨便google一下就能出來幾十上百篇文章署咽,當然這其中有寫的好的近顷,也有濫竽充數(shù)的。前面在公眾號推出了Material Design 的系列文章宁否,就有讀者留言窒升,希望出一篇關于沉浸式的文章。因此這篇文章就整理總結一下各個版本的實現(xiàn)原理慕匠,順便為大家推薦一個我覺得很方便的一個庫饱须。

二、沉浸式的一般套路

在介紹這個方便的輪子之前台谊,我們先一起來回顧一下實現(xiàn)沉浸式狀態(tài)欄的一般套路冤寿。在Android上,關于對StatusBar(狀態(tài)欄)的操作青伤,一直都在不斷改善督怜,并且表現(xiàn)越來越好,在Android4.4 以下狠角,我們可以對StatusBar和 NavigationBar進行顯示和隱藏操作号杠。但是直到Android4.4,我們才能真正意義上的實現(xiàn)沉浸式狀態(tài)欄。從Android4.4 到現(xiàn)在(Android 7.1),關于沉浸式大概可以分成三個階段:

  • Android4.4(API 19) - Android 5.0(API 21): 這個階段可以實現(xiàn)沉浸式姨蟋,但是表現(xiàn)得還不是很好屉凯,實現(xiàn)方式為: 通過FLAG_TRANSLUCENT_STATUS設置狀態(tài)欄為透明并且為全屏模式,然后通過添加一個與StatusBar 一樣大小的View眼溶,將View 的 background 設置為我們想要的顏色悠砚,從而來實現(xiàn)沉浸式。

  • Android 5.0(API 21)以上版本: 在Android 5.0的時候堂飞,加入了一個重要的屬性和方法 android:statusBarColor (對應方法為 setStatusBarColor)灌旧,通過這個方法我們就可以輕松實現(xiàn)沉浸式。也就是說绰筛,從Android5.0開始枢泰,系統(tǒng)才真正的支持沉浸式。

  • Android 6.0(API 23)以上版本:其實Android6.0以上的實現(xiàn)方式和Android 5.0 +是一樣铝噩,為什么要將它歸為一個單獨重要的階段呢衡蚂?是因為從Android 6.0(API 23)開始,我們可以改狀態(tài)欄的繪制模式骏庸,可以顯示白色或淺黑色的內容和圖標(除了魅族手機毛甲,魅族自家有做源碼更改,6.0以下就能實現(xiàn))

大概就是這個三個階段具被,那么接下來我們就看一下這個三個階段分別是如何來實現(xiàn)的玻募。

2.1 Android4.4(API 19) - Android 5.0(API 21)實現(xiàn)沉浸式的方式

Android 4.4 為什么能夠實現(xiàn)沉浸式的效果呢?因為在Android 4.4 新增了一個重要的屬性:FLAG_TRANSLUCENT_STATUS

 /**
         * 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;

解釋:設置狀態(tài)欄透明硬猫,并且變?yōu)槿聊J讲构俊I厦娴慕忉屢呀?jīng)說得很清楚了改执,當window的這個屬性有效的時候啸蜜,會自動設置 system ui visibility的標志SYSTEM_UI_FLAG_LAYOUT_STABLESYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

有兩種方式實現(xiàn)這個屬性:

可以在代碼中設置辈挂,如下:

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

當然也可以在theme 中設置屬性windowTranslucentStatus,如下:

android:windowTranslucentStatus

效果如下:

效果如上圖衬横,可以看出,沉浸式的效果是出來了终蒂,但是也有一個問題蜂林,我們的標題欄和狀態(tài)欄重疊了,相當于整個布局上移了StatusBar 的高度拇泣。

為了讓標題欄回到原來的位置噪叙,我們在標題欄的上方添加一個大小和StatusBar大小一樣的View,View 的BackgroundColor 為標題欄一樣的顏色,這個View起到一個占位的作用霉翔。這個時候睁蕾,標題欄就會下移StatusBar的高度,回到正常的位置。

添加如下代碼:

       //獲取windowphone下的decorView
        ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        int       count     = decorView.getChildCount();
        //判斷是否已經(jīng)添加了statusBarView
        if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
            decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
        } else {
            //新建一個和狀態(tài)欄高寬的view
            StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
            decorView.addView(statusView);
        }
        ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
        //rootview不會為狀態(tài)欄留出狀態(tài)欄空間
        ViewCompat.setFitsSystemWindows(rootView,true);
        rootView.setClipToPadding(true);

創(chuàng)建和status bar 一樣大小的View的代碼如下:

 private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) {
        // 繪制一個和狀態(tài)欄一樣高的矩形
        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子眶。

添加上述代碼后瀑凝,效果如下:


通過以上就可以實現(xiàn)Android 4.4 上的沉浸式狀態(tài)欄。

另外臭杰,如果是一張圖片延伸到狀態(tài)欄的話粤咪,直接設置FLAG_TRANSLUCENT_STATUS就可以了,如下:

小結:Android4.4上實現(xiàn)沉浸式狀態(tài)欄的套路是:為window添加FLAG_TRANSLUCENT_STATUS Flag,然后添加一個和status bar 一樣大小的View 站位渴杆,從而讓讓標題欄不會與status bar 重疊寥枝。而圖片延伸到狀態(tài)欄只需要設置FLAG_TRANSLUCENT_STATUS就OK。

前面說過将塑,沉浸式在Android4.4 - Android5.0 之間的版本表現(xiàn)得不是很好脉顿,從上面貼的幾張圖就可以看出,狀態(tài)欄的頂部有一個漸變点寥,會顯示出黑色的陰影(底部的導航欄也是一樣的效果)艾疟,在Android 5.0 版本已經(jīng)被修復了。

2.2 Android 5.0(API 21)以上實現(xiàn)沉浸式的方式

Android 5.0 是一個里程碑式的版本敢辩,從Android 5.0開始蔽莱,Google 推出了全新的設計規(guī)范 Material Design,并且原生控件就可以實現(xiàn)一些炫酷的UI動效。從這個版本開始戚长,google 加入了一個比較重要的方法setStatusBarColor (對應屬性:android:statusBarColor),通過這個方法盗冷,可以很輕松地實現(xiàn)沉浸式狀態(tài)欄。方法如下:

 /**
     * 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負責系統(tǒng)bar的background 繪制蟆湖,繪制透明背景的系統(tǒng)bar(狀態(tài)欄和導航欄)故爵,然后用getStatusBarColor()getNavigationBarColor()的顏色填充相應的區(qū)域。這就是Android 5.0 以上實現(xiàn)沉浸式導航欄的原理隅津。

實現(xiàn)沉浸式添加如下代碼:

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>

效果和上面代碼中添加的效果一樣,這里就不貼效果圖了伦仍。

圖片延伸到狀態(tài)欄

在Android 5.0 使圖片延伸到狀態(tài)欄结窘,只需設置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 + 實現(xiàn)狀態(tài)欄字色和圖標淺黑色

使用沉浸式的時候會遇到一個問題,那就是Android 系統(tǒng)狀態(tài)欄的字色和圖標顏色為白色充蓝,當我的主題色或者圖片接近白色或者為淺色的時候隧枫,狀態(tài)欄上的內容就看不清了。 ,這個問題在Android 6.0的時候得到了解決悠垛。Android 6.0 新添加了一個屬性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

解釋:為setSystemUiVisibility(int)方法添加的Flag,請求status bar 繪制模式线定,它可以兼容亮色背景的status bar 。要在設置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDSflag ,同時清除了FLAG_TRANSLUCENT_STATUSflag 才會生效确买。

添加如下代碼:

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以上 狀態(tài)欄字色和圖標為淺黑色-->
        <item name="android:windowLightStatusBar">true</item>
    </style>

注意:主題要放在values-v23文件夾下:

三、輪子StatusBarUtil

通過上面的介紹湾趾,其實將各個版本實現(xiàn)沉浸式的方式和原理都講完了芭商。但是或許當你真正去實踐沉浸式狀態(tài)欄的時候,你會感覺到無從下手搀缠,因此铛楣,我給大家推薦一個輪子StatusBarUtil,Github:https://github.com/laobie/StatusBarUtil艺普。

為什么會推薦這個庫呢簸州?因為這個庫就只有一個類StatusBarUtil,使用起來很方便,就像一個工具類一樣使用歧譬。里面封裝了很多靜態(tài)方法岸浑,直接使用就好。自己添加也很方便瑰步。介紹一下使用的一些場景:

需要在setContentView()之后調用:

setContentView(R.layout.main_activity);
...
StatusBarUtil.setColor(MainActivity.this, mColor);
  • 1,設置狀態(tài)欄顏色
StatusBarUtil.setColor(Activity activity, int color)
  • 2,設置狀態(tài)欄半透明
StatusBarUtil.setTranslucent(Activity activity, int statusBarAlpha)
  • 3,設置狀態(tài)欄全透明
StatusBarUtil.setTransparent(Activity activity)
  • 4,為包含 DrawerLayout 的界面設置狀態(tài)欄顏色(也可以設置半透明和全透明)
StatusBarUtil.setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color)

  • 5,為使用 ImageView 作為頭部的界面設置狀態(tài)欄透明(常用的場景為詳情頁的Header部分)
StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView)
  • 6矢洲,在 Fragment 中使用
status_uti

四、最后

以上就是對于沉浸式狀態(tài)欄的一些總結缩焦,希望可以給還沒有使用沉浸式的同學一些幫助读虏。如果你已經(jīng)使用過沉浸式狀態(tài)欄,也不仿看一下袁滥,可以對各個版本實現(xiàn)的原理有一個更深的了解盖桥。最后,推薦了一個不錯的庫呻拌,更確切的說葱轩,應該是一個不錯的工具類睦焕。如有問題藐握,歡迎交流。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末垃喊,一起剝皮案震驚了整個濱河市猾普,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌本谜,老刑警劉巖初家,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡溜在,警方通過查閱死者的電腦和手機陌知,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掖肋,“玉大人仆葡,你說我怎么就攤上這事≈玖” “怎么了沿盅?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纫溃。 經(jīng)常有香客問我腰涧,道長,這世上最難降的妖魔是什么紊浩? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任窖铡,我火速辦了婚禮,結果婚禮上坊谁,老公的妹妹穿的比我還像新娘万伤。我一直安慰自己,他們只是感情好呜袁,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布敌买。 她就那樣靜靜地躺著,像睡著了一般阶界。 火紅的嫁衣襯著肌膚如雪虹钮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天膘融,我揣著相機與錄音芙粱,去河邊找鬼。 笑死氧映,一個胖子當著我的面吹牛春畔,可吹牛的內容都是我干的。 我是一名探鬼主播岛都,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼律姨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了臼疫?” 一聲冷哼從身側響起择份,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烫堤,沒想到半個月后荣赶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凤价,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年拔创,在試婚紗的時候發(fā)現(xiàn)自己被綠了利诺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡剩燥,死狀恐怖立轧,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情躏吊,我是刑警寧澤氛改,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站比伏,受9級特大地震影響胜卤,放射性物質發(fā)生泄漏。R本人自食惡果不足惜赁项,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一葛躏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悠菜,春花似錦舰攒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芬骄,卻和暖如春猾愿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背账阻。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工蒂秘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人淘太。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓姻僧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蒲牧。 傳聞我的和親對象是個殘疾皇子撇贺,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容