Android 系統狀態欄沉浸式/透明化完整解決方案

前言

網上已經有很多有關於系統狀態欄的解決方案,這篇文章也不會有什麼新奇的解決方案,都是本人經過自己試驗,統計提煉出來的相對靠譜的一套解決方案.
如果是android大牛可以忽略本文,怕讓您賤笑.只面向小白,幫助小白減少摸索的時間.

關於術語

網上有很多爭論:

你這狀態欄是變色龍狀態欄,不是沉浸式的
這應該是沉浸式的狀態欄吧,系統欄與actionbar顏色設爲一致

我只想說去你妹的,老子只要自己的app的狀態欄能和主題顏色一致就行了,定義那麼多術語,讓我等小白情以何堪?
吐槽歸吐槽,但還是不得不去試着理解下這些術語怎麼來的,引用這裏的一段話:

  1. 沉浸式全屏模式
    隱藏status bar(狀態欄)使屏幕全屏,讓Activity接收所有的(整個屏幕的)觸摸事件。
  2. 透明化系統狀態欄
    透明化系統狀態欄,使得佈局侵入系統欄的後面,必須啓用fitsSystemWindows屬性來調整佈局才不至於被系統欄覆蓋。

因此,我就這樣理解了:

沉浸式不就是隱藏狀態欄嘛,狀態欄不見了?這不就是app全屏模式嘛?wtf?

而透明式式狀態欄就是讓app的內容佈局可以擴展到系統狀態欄?這裏有個問題就是爲什麼能在系統狀態欄還顯示的情況下,將內容佈局擴展到系統狀態欄?恩,這應該很好理解,就是Z座標系的作用了,系統狀態欄是覆蓋在內容佈局上面的,並且是透明的。

貌似這裏所謂透明化系統狀態欄纔是本菜想要的,不管了,現在開始一一試驗,至於這概念理解的對不對,管他呢?那到底應該叫什麼,那我就叫自適應狀態欄,行不行?

前提條件

讓系統狀態欄顏色隨app主題顏色變化而變化這一設計,毫無疑問,也是向ios學習的:從android4.4開始引進的,並且在5.0進行了改進。因此,也只能將這一特性應用在android4.4以上的手機,無法做到全部適配。記得stormzhang(貌似是)曾說過:

作爲一個android程序員,還能有什麼比做出ios風格的app更感到悲哀的呢?哎...

兩種情況下的解決方案:

  1. 使用toolbar
    這種方案相對簡單,個人喜歡這種方案,本菜雖菜,但喜歡緊跟潮流。toolbar太好用了,
  2. 不使用toolbar

1. 使用toolbar的解決方案

這個方法參照了這裏,薄荷app的toolbar適配方案

其基本原理就是:
theme裏添加style: <item name="android:windowTranslucentStatus"> true </item>後,包含toolbar的內容佈局就可以擴展至系統狀態欄,狀態欄會覆蓋在toolbar上,如果此時使用android:fitsSystemWindows="true",就可以調整內容佈局(估計也是在根佈局上加padding)恢復到原來位置.但是,上面的解決方案確是給toolbar加上一個padding-top="25dp",這樣就可以做到系統狀態欄的顏色和toolbar的顏色保持一致.具體方案可以參照上面的薄荷app的方案鏈接.


簡述下步驟(只是簡述,有疑問請參照上面薄荷app的鏈接即可):

  1. 引入v7包,並在佈局裏添加toolbar
    compilecom.android.support:appcompat-v7:22.2.1
  2. 在代碼中設置透明化:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
     WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
     local LayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
    }
    當然也可以在theme的樣式文件裏添加style:<item name="android:windowTranslucentStatus">true</item>,效果相同,但是大神們都說樣式文件裏設置在某些型號裏不生效.ok,大家都在代碼裏設置就好了
  3. 給toolbar加上padding-top,toolbar代碼如下
    <android.support.v7.widget.Toolbar android:id="@+id/toolbar" 
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingTop="@dimen/toolbar_padding_top"
     app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
     app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
     android:background="#30469b">
         <TextView android:layout_gravity="center" 
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:textSize="20sp"
           android:text="@string/app_name"/>
    </android.support.v7.widget.Toolbar>
    4.其中android:paddingTop="@dimen/toolbar_padding_top"要在values中的styles文件裏設爲0dp,在values-v19的styles裏設爲25dp,原因不多說了

這樣就可以達成了我們的目標,如果只是這樣也就罷了,按照上面做就可以了,關鍵是本菜是喜歡緊跟潮流的,使用MD風格的DrawerLayout+NavigationView時,在android4.4的手機下,就會變這樣了:


android4.4上的效果


很明顯,drawerlayout並沒用被擴展至系統狀態欄,但在android5.0以上效果還是可以的,這讓我很奇怪,只能歸咎於5.0的優化了


android5.0上的效果


經過各種折騰終於想起來,可以把fitsSystemWindows的特性用在drawerlayout上試試,最後發現居然可以,最終將設置windowTranslucentStatus的代碼調整如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();    
    local LayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
        //將側邊欄頂部延伸至status bar
        mDrawerLayout.setFitsSystemWindows(true);        
        //將主頁面頂部延伸至status bar;雖默認爲false,但經測試,DrawerLayout需顯示設置
        mDrawerLayout.setClipToPadding(false);
    }
}

最終android4.4上也可以顯示正常:


android4.4上修正後的效果

2. 不使用toolbar的解決方案

不使用toolbar時,而是actionbar時,因爲actionbar不好定製,所以無法採用上面那個方法,只能採用其它方法,這裏的方案主要參考這裏:Translucent System Bar 的最佳實踐
這篇簡書看的本菜暈乎乎的,仔細看下來,其實都是基於一個原理:
不管有沒有actionbar,內容佈局的背景顏色一律設爲主題顏色,然後有actionbar的話,就將actionbar與內容佈局的背景顏色同時設爲主題顏色,然後,每個內容佈局的根佈局都要設上fitsSystemWindows="true"進行調整,感覺超麻煩有沒有?


不說多少,簡述步驟:

  1. 在代碼中設置透明化,步驟同上
  2. 設置內容佈局的根佈局的背景顏色爲主題顏色,同時設置fitsSystemWindows="true"
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/colorPrimary"
     android:fitsSystemWindows="true" 
     android:orientation="vertical">
  3. 在內容佈局的下面再設置一層內容佈局,設背景顏色爲白色(或其它顏色):
    <LinearLayout    android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/c_light_white"
     android:gravity="center"
     android:orientation="vertical">

至此,這種方案也完成了,看下效果:


android4.4上的效果

可以看出,這種方案一般情況下,還是可行的,但是有三個問題:

  1. 如果用上drawerlayout+navigationview,actionbar就會覆蓋在側邊欄上(如上圖),暫時未找到解決方案,但是我想說你都用drawerlayout+navigationview了,爲何不用toolbar,因此這個問題應該不是問題,況且還可以使用其它的側邊欄實現方式,各位道友可以試試
  2. 這種方案在每個根佈局上都要設fitsSystemWindows="true"進行調整,當然上面也有優化方案,可仍然覺得很麻煩,
  3. 每個根佈局裏都要多加的一層佈局來覆蓋根佈局的背景主題顏色

因此,這種方案的確不是上上之選.

總結

本文主要在考慮使用標題欄(actionbar/toolbar)的情況下,做出的方案,當然你也可以自定義標題欄,或者不使用標題欄;其實都可以基於上面一樣的道理:

在狀態欄透明化的前提下,調整頂部view的padding-top,來達到狀態欄自適應一體化的目的

網上還有其它蠻多的解決方案,如:

  1. 使用開源庫SystemBarTint,這個庫也挺不錯的,可以動態改變系統狀態欄顏色,但是作者已經2年沒有維護了,現在技術更新迭代這麼快,鬼知道這個庫會不會出現什麼問題,因此可以放棄使用了
  2. 如果不怕麻煩,還可以new一個高度和狀態欄一樣高的view,插入到內容佈局的上面,但是,想想都覺得麻煩,我也懶得試了


發佈了19 篇原創文章 · 獲贊 18 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章