Anroid沉浸式狀態(tài)欄

概要

Metarial Design是2014年Google IO的一個(gè)重點(diǎn),在過去的兩年時(shí)光里,越來(lái)越多的公司已經(jīng)開始認(rèn)可MD設(shè)計(jì)規(guī)范。在dribbble上可以越來(lái)越多的設(shè)計(jì)師開始投入到MD設(shè)計(jì)實(shí)踐中,MD設(shè)計(jì)規(guī)范終于有底氣可以和IOS的設(shè)計(jì)規(guī)范對(duì)抗啦Android程序員可以很叫囂滴告訴設(shè)計(jì)師這就是Android的設(shè)計(jì)規(guī)范。

很少寫Material Design的東西,今天趁著手熱,在Material化財(cái)經(jīng)APP的時(shí)候,看了些透明狀態(tài)欄/沉浸式狀態(tài)欄的東西,覺得自己可能還有很多不足之處只是希望能分享出來(lái),一方面是自己的學(xué)習(xí)成果,另一方面是希望大家指正自己在理解的不到位或者錯(cuò)誤。

先放一張我的五兒子手機(jī)原生的短信截圖:

圖1

從上到下,一次是狀態(tài)欄,內(nèi)容View,導(dǎo)航欄(有些機(jī)器上不一定有導(dǎo)航欄這個(gè)虛擬欄),可以看到狀態(tài)欄是彩色的,不是以前那種黑乎乎的狀態(tài)欄,現(xiàn)在你也可以定制自己的狀態(tài)欄了。

現(xiàn)在我們就來(lái)看下我手機(jī)上裝的APP的一些截圖:
<span id="pic2">

圖2

</span>
這個(gè)五個(gè)應(yīng)用分別是網(wǎng)易新聞、豌豆莢、微信、小米天氣、小氣天氣。

關(guān)于這個(gè)狀態(tài)欄變色到底叫「Immersive Mode」/「Translucent Bars」有興趣可以去 為什么在國(guó)內(nèi)會(huì)有很多用戶把 ?透明欄?(Translucent Bars)稱作 ?沉浸式頂欄??以及何為沉浸模式,沉浸式頂欄,變色龍狀態(tài)欄,這個(gè)歷史原因我們就沒法去說大家錯(cuò)誤,所有就錯(cuò)說錯(cuò)有了沉浸式狀態(tài)欄一說。

在5.0之后我們是可以通過v7包下的Theme.AppCompat一些列主題為APP的頁(yè)面設(shè)置Activity的的狀態(tài)欄,但是為了兼容低版本的我們放棄這種方式。為了能定制自己的狀態(tài)欄,我們可以手動(dòng)設(shè)置狀態(tài)欄的顏色,可以隨時(shí)改變狀態(tài)欄的透明度等,所以我們需要自己來(lái)定制一套可行的方案。

實(shí)現(xiàn)

準(zhǔn)備

分類

  1. 全屏模式和著色模式
    根據(jù)內(nèi)容延伸的角度可以分為兩類:全屏模式和著色模式。其中,圖2 中前三個(gè)頁(yè)面都是狀態(tài)欄固定在上方,無(wú)論下面怎么滑動(dòng),內(nèi)部View都是那一塊固定的大小區(qū)域滑動(dòng),由于狀態(tài)欄是固定在一定位置且有著色,我們稱之為著色模式,而圖2中后兩個(gè)頁(yè)面截圖中,內(nèi)容View和狀態(tài)欄像放在一個(gè)FrameLayout一樣,是層疊關(guān)系并且狀態(tài)欄是透明,內(nèi)容View可以延伸到狀態(tài)欄,我們稱之為全屏模式。

  2. 透明狀態(tài)欄和彩色狀態(tài)欄
    根據(jù)狀態(tài)欄的顏色,可以分為狀態(tài)欄透明和不透明(網(wǎng)易新聞、小米天氣都是透明,而豌豆莢、wechat都是不透明)。
    以上兩種分為是不同維度的,從不同維度來(lái)看可以組合如下圖:

setFitsSystemWindows

在android doc是這么描述的:

void setFitsSystemWindows (boolean fitSystemWindows)
Sets whether or not this view should account for system screen decorations such as the status bar and inset its content; that is, controlling whether the default implementation of fitSystemWindows(Rect) will be executed. See that method for more details.

Note that if you are providing your own implementation of fitSystemWindows(Rect), then there is no need to set this flag to true -- your implementation will be overriding the default implementation that checks this flag.

大概意思是:setFitsSystemWindows用來(lái)設(shè)置影響系統(tǒng)的工具欄如狀態(tài)欄,決定了這個(gè)view是否插入到它的ContentView。當(dāng)您設(shè)置了fitSystemWindows(Rect)而沒有將setFitsSystemWindows設(shè)置為true,你對(duì)fitSystemWindows(Rect)設(shè)置是無(wú)效的.

該屬性可以設(shè)置是否為系統(tǒng) View 預(yù)留出空間, 當(dāng)設(shè)置為 true 時(shí),會(huì)預(yù)留出狀態(tài)欄的空間。

由于這個(gè)實(shí)在API14(4.0)之后的函數(shù),為了兼容低版本,才有V4里面的

 ViewCompat.setFitsSystemWindows(rootView,false);

透明狀態(tài)欄

由于Android 4.4才加入透明狀態(tài)欄,Android 5.0之后可以直接設(shè)置狀態(tài)欄和導(dǎo)航欄,而不是之前的黑乎乎的狀態(tài)欄,但是,在4.4以下的系統(tǒng)上,想自己定義狀態(tài)欄就無(wú)能為力了。所以,我們將Android 4.4和Android5.0視為邊界。

Android 4.4設(shè)置透明狀態(tài)欄

設(shè)置方法有兩種:

代碼

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // 設(shè)置狀態(tài)欄透明
             activity.getWindow()
                .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            
}

XML

在values-v19文件夾下,為activity的Style 添加一個(gè)屬性:

<resources>

   <style name="AppTheme" parent="@style/BaseAppTheme">
       <item name="android:windowTranslucentStatus">true</item>
   </style>
</resources>

5.0+透明狀態(tài)欄

不過對(duì)于5.0系統(tǒng),上面的設(shè)置后的結(jié)果可能不是透明哦(在原生機(jī)器是不透明的,但是在小米的是透明的,估計(jì)MIUI做了一些優(yōu)化工作)

若是要完全透明,就需要看額外處理,在內(nèi)容延伸到狀態(tài)欄一節(jié)有介紹。

當(dāng)然了你也可以用5.0的setStatusBarColor

<span id="5status">全屏模式的透明狀態(tài)欄</span>

Window window = activity.getWindow();
//設(shè)置透明狀態(tài)欄,這樣才能讓 ContentView 向上
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 

//需要設(shè)置這個(gè) flag 才能調(diào)用 setStatusBarColor 來(lái)設(shè)置狀態(tài)欄顏色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
//設(shè)置狀態(tài)欄顏色
window.setStatusBarColor(statusColor);

//為了設(shè)置全屏
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
    //注意不是設(shè)置 ContentView 的 FitsSystemWindows, 而是設(shè)置 ContentView 的第一個(gè)子 View . 使其不為系統(tǒng) View 預(yù)留空間.
    ViewCompat.setFitsSystemWindows(mChildView, false);
    
}

ViewCompat.setFitsSystemWindows(mChildView, false)中的第二個(gè)參數(shù)設(shè)置為false就是全屏模式,而設(shè)置成true。像上述實(shí)例中, ViewCompat.setFitsSystemWindows(mChildView, false)就是說mChildView可以直接延伸到phoneWindow的頂部,相當(dāng)于小米天氣的那種效果。

彩色狀態(tài)欄

有透明狀態(tài)欄,就有彩色狀態(tài)欄。
在5.0+設(shè)置狀態(tài)欄很簡(jiǎn)單就參照全屏模式的透明狀態(tài)欄中的代碼做修改window.setStatusBarColor(int color),而對(duì)于Android 4.4--5.0的怎么辦呢,Android4.4是提供setStatusBarColor這個(gè)方法的。

我們就想到了在上面提到的全屏透明狀態(tài)欄的基礎(chǔ)上加一個(gè)和狀態(tài)欄一樣高度的空白View放到頂部。

好了說干就干:

        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
 //添加一個(gè)空白的view到手機(jī)屏幕的頂部
addStatusBarBehind(activity, color, statusBarAlpha);
public static void addStatusBarBehind(Activity activity, int color, int statusBarAlpha) {
        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);
        }
        setRootView(activity);
    }

全屏模式

全屏模式,內(nèi)容延伸到狀態(tài)欄類似與小米天氣的APP,先考慮下怎么做?

答案:將內(nèi)容移到狀態(tài)欄下,并且狀態(tài)欄背景透明.

4.4--5.0

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // 設(shè)置狀態(tài)欄透明
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //  設(shè)置根布局的參數(shù)
            ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
            ViewCompat.setFitsSystemWindows(rootView,false);
            rootView.setClipToPadding(true);
        }

其實(shí)就先將狀態(tài)欄設(shè)置了透明activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS),而后可以直接設(shè)置內(nèi)容的根View來(lái)直接設(shè)置ViewCompat.setFitsSystemWindows(rootView,false),這樣就可以直接講根rootView直接頂上去,和狀態(tài)欄的頂部對(duì)齊。

5.0+

在Android 4.4上設(shè)置透明狀態(tài)欄,在5.0上依然可以正常顯示,利用5.0實(shí)現(xiàn)的全屏模式的透明狀態(tài)欄不過狀態(tài)欄實(shí)際上并不完全為透明色,會(huì)有些許灰色。一般情況下,這個(gè)使我們能接受的,如微信、QQ等都是狀態(tài)欄顏色暗與下面的Toolbar的。

若是能通過Activity的Theme的colorPrimaryDark設(shè)狀態(tài)欄顏色顏色設(shè)置,也是可行的,但是若你must實(shí)現(xiàn)透明額狀態(tài)欄,也只能出狠招了。

Window window = activity.getWindow(); 

window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS|
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);           window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);    

setSystemUiVisibility這個(gè)可以參考Using Immersive Full-Screen Mode。


這樣的組合,讓我們可以按照自己的需求來(lái)定制自己的狀態(tài)欄,隨后會(huì)開源自己封裝的開源庫(kù)工供大家參考。

參考文章

  1. Using Immersive Full-Screen Mode
  1. Android實(shí)現(xiàn)沉浸式狀態(tài)欄

  2. Android-transulcent-status-bar

  3. Android狀態(tài)欄合集-管你透不透明

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容