1. 程式人生 > >Android狀態列著色-透明狀態列

Android狀態列著色-透明狀態列

最近專案上有需求 ,要求狀態列透明化 。還有需求是拖動狀態列標題一下的內容,標題欄的顏色要變化 。這裡所謂的既是狀態列著色,也是我們經常聽到的沉浸式狀態列,關於沉浸式的稱呼網上也有很多吐槽的,這裡就不做過多討論了,以下我們統稱狀態列著色,這樣我覺得更加容易理解。

從Android4.4開始,才可以實現狀態列著色,並且從5.0開始系統更加完善了這一功能,可直接在主題中設定<item name="colorPrimaryDark">@color/colorPrimaryDark</item>或者getWindow().setStatusBarColor(color)來實現,但畢竟4.4+的機器還有很大的佔比,所以就有必要尋求其它的解決方案。

第一種方案:

1、首先將手機手機狀態列透明化:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0及以上
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility
(option); getWindow().setStatusBarColor(Color.TRANSPARENT); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4到5.0 WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes(); localLayoutParams.flags = (WindowManager.LayoutParams
.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags); }

在相應的Activity或基類執行這段程式碼就ok了。
可見在4.4到5.0的系統、5.0及以上系統的處理方式有所不同,除了這種程式碼修改額方式外,還可以通過主題來修改,需要在values、values-v19、values-v21目錄下分別建立相應的主題:

//values
<style name="TranslucentTheme" parent="AppTheme"></style>

//values-v19
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">false</item>
</style>

//values-v21
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">false</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
</style>

給相應Activity或Application設定該主題就ok了。
兩種方式根據需求選擇就好了,到這裡我們就完成了第一步,將狀態列透明化了。

2、給狀態列著色
完成了第一步,我們開始給狀態列加上想要的色彩吧!
將狀態列透明化後,直接執行專案會發現介面佈局直接延伸到狀態列,針對這種情況首先可以在佈局檔案使用android:fitsSystemWindows="true"屬性讓佈局不延伸到狀態列,接下來新增一個和狀態列高、寬相同的指定顏色View來覆蓋被透明化的狀態列,或者使佈局的背景顏色為需要的狀態列顏色。這兩種方式在後邊會說到,這裡我們先看另外一種方式,也是個人比較喜歡的。我們分一下幾種場景來討論:

先做一些準備工作,在values、values-v19目錄新增如下尺寸:

//values
<dimen name="padding_top">0dp</dimen>

//values-v19
<dimen name="padding_top">25dp</dimen>

關於25dp,在有些系統上可能有誤差,這裡不做討論!

2.1 頁面頂部使用Toolbar(或自定義title)
一般情況狀態列的顏色和Toolbar的顏色相同,既然狀態列透明化後,佈局頁面延伸到了狀態列,何不給Toolbar加上一個狀態列高度的頂部padding呢:

<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:paddingTop="@dimen/padding_top"
        android:theme="@style/AppTheme.AppBarOverlay" />

效果如下:


1

至於自定義title的情況經測試也ok的,圖就不貼了,有興趣可看程式碼。

2.2、 DrawerLayout + NavigationView + Toolbar
同樣先給Toolbar設定頂部padding,在4.4系統上看下效果:


2


NavigationView竟然沒延伸到狀態列,好吧,繼續修改,當系統版本小於5.0時,進行如下設定:

private void navViewToTop() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            mDrawerLayout.setFitsSystemWindows(true);
            mDrawerLayout.setClipToPadding(false);
        }
    }

再看效果:


3

2.3、頁面頂部是一張圖片
這種其實是最簡單的,因為狀態列透明化後,佈局已經延伸到狀態,所以不需要其它額外操作:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="@mipmap/top_image" />
</LinearLayout>

效果如下:


4

2.4、頁面底部切換Tab + fragment
某些情況下,當我們的頁面採用底部切換Tab + 多個fragment時,可能每個fragment的頂部顏色不一樣。如何實現狀態列顏色跟隨fragment切換來變化呢?其實原理和2.1類似,這裡我們每個fragment採用自定義的Title,先看FragmentOne的佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff9900"
        android:paddingTop="@dimen/padding_top">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="fragment one" />
    </LinearLayout>
</LinearLayout>

我們設定Title的背景為橙黃色、同時設定paddingTop,FragmentTwo的佈局類似,只是Title的背景為藍色。然後將兩個Fragment新增到Activity中,最後看下切換的效果:


5

嗯,效果還是不錯的,沒有延遲的情況!可惜沒早點發掘這種方式,以前的方案效果略不理想。

第二種方案:

在方案一中,我們沒有使用android:fitsSystemWindows="true"屬性,而是將佈局延伸到狀態列來處理,這次我們使用android:fitsSystemWindows="true"屬性,不讓佈局延伸到狀態列,這時狀態列就是透明的,然後新增一個和狀態列高、寬相同的指定顏色View來覆蓋被透明化的狀態列。我們一步步來實現。

1、第一步還是先將狀態列透明化,方法同上。
2、在佈局檔案中新增android:fitsSystemWindows="true"屬性:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:title="第二種方案" />
</LinearLayout>

3、建立View並新增到狀態列:

private void addStatusBarView() {
        View view = new View(this);
        view.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                getStatusBarHeight(this));
        ViewGroup decorView = (ViewGroup) findViewById(android.R.id.content);
        decorView.addView(view, params);
    }

原理很簡單,但是要額外寫這些程式碼。。。最後看下效果:


6

第三種方案:

和方案二類似,同樣使用android:fitsSystemWindows="true"屬性,再修改佈局檔案的根佈局為需要的狀態列顏色,因根佈局的顏色被修改,所以你需要在裡邊多巢狀一層佈局,來指定介面的主背景色,比如白色等等,否則就和狀態列顏色一樣了。說起來有點抽象,還是看具體的例子吧:
1、先將狀態列透明化,方法同上。
2、修改佈局檔案:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff9900"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:orientation="vertical">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ff9900"
            android:theme="@style/AppTheme.AppBarOverlay"
            app:title="第三種方案" />
    </LinearLayout>
</RelativeLayout>

修改完了,看效果:


如果專案有幾十個介面,這樣的方式修改起來還是挺累的,你還要考慮各種巢狀問題。

後兩種方案的例子相對簡單,有興趣的話你可以嘗試更多的場景!

三種方式如何選擇,相信到這裡你應該有答案了吧,我個人更喜歡第一種!
如果你有更好的方案,歡迎指點哦!

QQ交流群 :232203809,歡迎入群 
這裡寫圖片描述
微信公眾號:終端研發部 
(歡迎關注學習和交流)