徹底搞定Android Kitkat+沉浸式狀態(tài)欄效果

首先,我要實現(xiàn)的最終效果是這樣的,即在Android4.4及以上版本系統(tǒng)上,統(tǒng)一顯示為如下效果:


最終效果
最終效果

所謂“沉浸式”狀態(tài)欄

這里所說的沉浸式狀態(tài)欄,就是指上面的效果,狀態(tài)欄和Toolbar的顏色保持一致,融為一體的效果。

版本差異及解決方法

本文所用的示例使用的style風(fēng)格是NoActionBar的,標(biāo)題欄使用的是Toolbar控件,請知悉。

Android4.4

Android4.4以前的版本,狀態(tài)欄的顏色都是黑色的,而且無法修改;但一般APP的Toolbar都不會設(shè)置為黑色,于是,兩者
有十分明顯的顏色區(qū)分,各自占有不同的區(qū)域,填充不同的顏色。簡單的說,Android4.4以前的版本是無法做到
沉浸式的效果的(做系統(tǒng)開發(fā)的除外),所以如果想要統(tǒng)一風(fēng)格的話,可以設(shè)置APP最小支持的版本為4.4,如果
不行,就沒辦法了,只能4.4以前一個樣式,4.4及以后一個樣式。

Android4.4開始,新增了設(shè)置狀態(tài)欄背景色透明的屬性,新增的屬性是這兩個:

WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION

這兩個屬性分別設(shè)置狀態(tài)欄和導(dǎo)航欄背景色為全透明。(這里只討論狀態(tài)欄,只設(shè)置上面一個屬性就行,導(dǎo)航欄的類似)
實現(xiàn)方法很簡單,在Activity初始化時,調(diào)用以下代碼:

// Translucent status bar
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    Window window = getWindow();
    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}

由于是代碼設(shè)置,所以無法通過xml預(yù)覽到想要的結(jié)果,一定要在4.4真機上運行才能看到效果。

到這里可能存在兩個問題:

1. Toolbar把狀態(tài)欄的空間占用了,擠到一起。

2. 狀態(tài)欄和Toolbar并沒有完全融為一體,而是從上到下,由黑色漸變到Toolbar的顏色。

第一個現(xiàn)象是必現(xiàn)的,解決方法是在Toolbar的布局文件里加上一個屬性:

android:fitsSystemWindows="true"

這個屬性必須加在Toolbar或者Toolbar的父控件上,也就是,如果Toolbar直接寫在Activity的布局文件里,則在Toolbar上
加這個屬性,如果Toolbar是include到Activity的布局文件里,則可以加到Toolbar的父控件里;

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.chengsy.immersive.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:fitsSystemWindows="true"
        app:title="@string/app_name"
        app:titleTextColor="#FFFFFF">

    </android.support.v7.widget.Toolbar>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Hello World!" />

</LinearLayout>

上面這種情況,如果寫到linearlayout中,就會出現(xiàn)問題,StatusBar的背景色跟整個窗口的背景色一樣(或者跟桌面顏色一樣),而不是和Toolbar的
顏色一樣。效果如下:

屬性設(shè)置錯誤效果
屬性設(shè)置錯誤效果

第二個現(xiàn)象根據(jù)不同的系統(tǒng)廠商,效果不一樣,也就是不同的手機廠商做的不一樣,沒辦法,但是不是太影響沉浸式的效果。
效果如下:

漸變的StatusBar
漸變的StatusBar

總結(jié)一下,4.4版本,需要設(shè)置兩個地方來實現(xiàn)沉浸式效果:

  1. 設(shè)置狀態(tài)欄透明
  2. 設(shè)置Toolbar的fitsSystemWindows屬性為true

Android5.0

先看看通過上面的設(shè)置,程序運行在Android5.0的設(shè)備上是什么效果:
可能的效果也有兩個,一個是我們想要的效果,沉浸式,不再配圖了,另一個是這樣的:

在Android5.0部分機器上的效果
在Android5.0部分機器上的效果

這種效果是狀態(tài)欄的顏色上面覆蓋了一層半透明的顏色,不是全透明。當(dāng)然,原因你懂得,不同廠商系統(tǒng)設(shè)計師的idea是不一樣的,
但是這里說一下,谷歌官方的Mertial Design的設(shè)計規(guī)范是如上圖所示,并不是沉浸式的效果,但國內(nèi)的APP現(xiàn)在普遍比較
喜歡沉浸式的效果。

那么如果要統(tǒng)一5.0的效果跟4.4的效果保持一致,全部都是沉浸式該怎么辦???
這么辦---
首先,Android5.0開始,系統(tǒng)又新增了設(shè)置狀態(tài)欄顏色值的屬性和接口:

WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS

通過這個屬性來設(shè)置設(shè)置狀態(tài)欄的背景色,來實現(xiàn)兩者融為一體的效果,代碼實現(xiàn)如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        getWindow().setStatusBarColor(Color.TRANSPARENT);// SDK21
}

原理很簡單,首先要清空之前設(shè)置的FLAG_TRANSLUCENT_STATUS屬性,然后添加修改狀態(tài)欄背景色的屬性FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
,最后給狀態(tài)欄設(shè)置為全透明。

這里有坑,有的5.x的設(shè)備,如果調(diào)用這句代碼
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
狀態(tài)欄會變黑色,這時候需要去掉這句。但是去掉這句代碼,在6.0+系統(tǒng)上半透明的狀態(tài)欄又出現(xiàn)了。所以處理方法是判斷如果是某種特殊的系統(tǒng),
不調(diào)用上述代碼。

Android6.0

對于Android6.0及以后的系統(tǒng),對這方面的支持就已經(jīng)很完善和統(tǒng)一了,通過4.4設(shè)置的FLAG_TRANSLUCENT_STATUS屬性和
fitsSystemWindows屬性就可以達到想要的效果了,不需要做特殊處理,版本內(nèi)暫時不存在機型之間的差異。

但是6.0也不是完全沒新的東西(指的是狀態(tài)欄這一塊內(nèi)容),6.0新增了設(shè)置狀態(tài)欄里內(nèi)容色調(diào)的屬性和接口,通過設(shè)置如下屬性,可以把狀態(tài)欄的文字
色調(diào)由亮色改為暗色,亮色是白色,暗色是黑色:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

看名字感覺跟我的描素不一樣啊,其實,這個屬性是把狀態(tài)欄標(biāo)記為亮色調(diào),從而,系統(tǒng)會自動把狀態(tài)欄的文字內(nèi)容變?yōu)?br> 暗色調(diào),如果你的APP的Toolbar顏色是亮色的,再配上亮色的內(nèi)容就會不明顯,上面的代碼可以解決這個問題,自動將
狀態(tài)欄的內(nèi)容改為暗色調(diào)。

其他問題

  1. 輸入框的兼容問題

    如果想要頁面底部的輸入框可以被鍵盤頂起來,并且不影響頁面的沉浸式效果,需要做兩點:

     - AndroidManifest.xml文件配置鍵盤屬性:android:windowSoftInputMode="adjustResize"
     - Activity頁面根布局設(shè)置 android:fitsSystemWindows="true" 屬性
    

    布局代碼如下:

     <?xml version="1.0" encoding="utf-8"?>
     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:fitsSystemWindows="true"
         android:orientation="vertical"
         tools:context="com.chengsy.immersive.MainActivity">
     
         <android.support.v7.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:background="@color/colorPrimary"
             android:fitsSystemWindows="true"
             app:title="@string/app_name"
             app:titleTextColor="#FFFFFF">
     
         </android.support.v7.widget.Toolbar>
     
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_below="@+id/toolbar"
             android:gravity="bottom">
     
             <EditText
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="Hello World!" />
         </LinearLayout>
     
     </RelativeLayout>
    

    通過上面的處理,狀態(tài)欄的顏色不對了,變成了白色或者桌面的背景色,問題又來了。解決方法的原理就是給狀態(tài)欄填充上顏色,
    但是,給狀態(tài)欄修改顏色的屬性和接口在5.0才出現(xiàn),[4.4--5.0)版本的怎么辦?用SystemBarTintManager,Github上的開源庫,
    解決眼前的問題。使用很簡單,引用這個庫:

     compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
    

    代碼中設(shè)置:

     private SystemBarTintManager tintManager;
     
     tintManager = new SystemBarTintManager(this);
     tintManager.setStatusBarTintColor(getResources().getColor(R.color.colorPrimary));
     tintManager.setStatusBarTintEnabled(true);
    
  2. 其他第三方控件的兼容,如ActionMode等

    有用到這個的自己去查、去嘗試吧,這個控件好久不用了,也不知道什么效果,可以參考這篇文章里的解決方法:
    沉浸式狀態(tài)欄實現(xiàn)及遇到的坑

  3. 系統(tǒng)廠商的兼容,如MIUI系統(tǒng)等

    這里也介紹了MIUI系統(tǒng)的適配問題,供參考:
    沉浸式狀態(tài)欄實現(xiàn)及遇到的坑

總結(jié)

由于Android系統(tǒng)的開放性,以及系統(tǒng)廠商的不統(tǒng)一,導(dǎo)致Android系統(tǒng)的適配成為了另程序員頭疼的一大問題,沉浸式的效果同樣
不好做到完全統(tǒng)一樣式,只能盡力而為之。通過上面的操作,基本可以保證大多數(shù)機型和系統(tǒng)的沉浸式效果,但仍然有個別無法適配的
系統(tǒng)或機型,這里也無法一一列舉所有的情形,需要程序員們有針對性的設(shè)計代碼,解決問題。

這里給出自己總結(jié)的一個方法,可以在BaseActivity中調(diào)用:

首先,Toolbar要設(shè)置fitsSystemWindows屬性,如果頁面包含EditText,需同時在頁面根布局添加fitsSystemWindows屬性;
其次,引用SystemBarTintManager庫提供支持;
最后,調(diào)用如下代碼:

private SystemBarTintManager tintManager;
protected void initWindow() {
    // 4.4及以上版本設(shè)置狀態(tài)欄透明
    Window window = getWindow();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        // Translucent status bar
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    }

    // 解決4.4-5.0版本之間,頁面包含EditText無法適配的問題
    {
        // create our manager instance after the content view is set
        mTintManager = new SystemBarTintManager(this);
        // enable status bar tint
        mTintManager.setStatusBarTintEnabled(true);
        // enable navigation bar tint
        mTintManager.setNavigationBarTintEnabled(true);

        // 自定義狀態(tài)欄的顏色
        mTintManager.setStatusBarTintColor(getResources().getColor(R.color.colorPrimary));
    }

    // 解決[5.0-5.1.1]版本狀態(tài)欄沒有全透明的系統(tǒng)適配問題
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        // 解決部分5.x系統(tǒng)使用狀態(tài)欄透明屬性后狀態(tài)欄變黑色,不使用這句代碼,在6.0設(shè)備上又出現(xiàn)半透明狀態(tài)欄
        // 需要特殊處理
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        
        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);
    }
    
    // 把狀態(tài)欄標(biāo)記為淺色,然后狀態(tài)欄的字體顏色自動轉(zhuǎn)換為深色。
    // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    //     getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
    // }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,157評論 25 708
  • 前言 原文:http://blog.csdn.net/mybeta/article/details/5076032...
    naturs閱讀 23,304評論 8 70
  • 背景 上篇文章一個千萬量級的APP使用的一些第三方庫中,在說到一個使用很廣泛的滑動退出庫SwipeBackLayo...
    Ziv_xiao閱讀 17,050評論 22 127
  • 前言 首先請大家看幾張圖: 以上的效果,一般我們統(tǒng)稱為沉浸式狀態(tài)欄。其實,這種叫法不是很準(zhǔn)確,而且也沒有沉浸式狀態(tài)...
    宇是我閱讀 4,199評論 2 28
  • 交朋友這件小事,很像狗熊掰玉米。 從幼時到現(xiàn)在,掰一路扔一路。 末了駐足一看——咦,沒撈著幾個嘛?! 幼時和同院的...
    石長生之閱讀 865評論 3 2

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