Android 狀態欄操作,你想知道的都在這里了

hlim9135 7年前發布 | 19K 次閱讀 安卓開發 Android開發 移動開發

一直以來,iOS 設備上狀態欄背景色和圖標文字顏色的靈活可變性始終受到設計人員的青睞,有意地恰當地融入到 App 的各種界面設計當中,更好地提升用戶體驗。

由于系統的限制,在老版本的安卓系統中,Android App 無法做到這些,產生一些設計上的遺憾。幸運的是,自 4.4 版本(API 19)以后,Android 系統開始支持狀態欄的定制,并被納入 Android 設計規范當中,Android App 在設計上邁出了重要的一步。

“沉浸式狀態欄” VS “透明狀態欄”?

一般來說,Android 默認的狀態欄樣式表現為黑底白字,如果我們應用的標題欄背景色也為黑色,那就能與狀態欄很好地銜接在一起,體驗極佳。反之,如果為其他的顏色,整個界面的呈現效果就會大打折扣。

幸運的是,Android 4.4 版本開始,系統提供了相應的 API,支持狀態欄全透明化,界面 Content View 可以延伸到狀態欄上,填充狀態欄背景色。而在 Android 5.0 版本開始,系統在此基礎上做了進一步優化和規范,能夠實現動態改變狀態欄背景色,在透明度上默認呈現為半透明化,可定制化程度更高。

在此基礎上,最終要做到我們的應用呈現在 Android 各個系統版本上的效果如圖所示:

關于 Android 4.4 版本開始的狀態欄變化,許多人喜歡稱之為“沉浸式狀態欄”,但從系統提供的 API 命名上可以看出,核心詞匯為 “Translucent”,故準確來講,這種效果又應該稱之為“透明狀態欄”。可能對于設計師而言,沉浸式還是透明式的稱呼有所區別,但對于廣大開發者而言,無足輕重,我們所關注的應該是如何實現這種效果,并能夠很好的兼容到各個版本中。

相關 API 介紹

一般來說,目前在 Android 項目中我們都會使用 Toolbar 替代 ActionBar 來實現導航欄,除此之外,要實現透明狀態欄效果,還需要了解兩個相關 API,下面逐一介紹一下:

一:

<item name="android:windowTranslucentStatus">true</item>

也可以在代碼中實現(據說,在代碼中實現兼容性更好,style 資源中設置的方式在某些國產手機廠商定制的系統中存在一些問題):

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
    local LayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}

顧名思義,該屬性能夠實現透明狀態欄效果,是在 Android 4.4 版本引入的,也就是兼容至 API 19 及以上版本。使用該屬性設置主題后,內容布局向上延伸至狀態欄,并且在不同版本的系統中呈現效果也有所區別,如圖所示:

顯然,在 API 19 及更高版本上,Toolbar 內容延伸至狀態欄上去了,出現重疊問題,此時,就需要使用到另一個屬性了。

二:

android:fitsSystemWindows=”true”

Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.

用在 layout 布局文件中。官方文檔給出了很明確的介紹,大致是說能夠將使用該屬性的視圖與系統窗口(如狀態欄)保持一定的 padding 間距。所以如果我們在 toolbar 中設置了該屬性,就能夠解決 <item name="android:windowTranslucentStatus">true</item> 配置帶來的視圖延伸問題,使呈現效果達到文章開始所示圖中的效果。

使用案例分析

res/values/styles 文件中定義基礎主題樣式:

<style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar"/>
<style name="AppTheme" parent="BaseTheme">
</style>

res/values-v19/styles 文件中定義兼容主題樣式:

<style name="AppTheme" parent="BaseTheme">
    <item name="android:windowTranslucentStatus">true</item>
</style>

然后在 AndroidManifest.xml 文件中使用全局主題樣式:

  <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="Samples"
      android:supportsRtl="true"
      android:name=".MyApplication"
      android:theme="@style/AppTheme">

......

新建一個 layout 布局文件,單獨定義 toolbar 內容,在應用中的其他 Activity 界面布局中使用 include 標簽潛入引用:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/tb_toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?actionBarSize"
    android:background="@color/colorPrimary"
    android:fitsSystemWindows="true"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:title="@string/app_name"
    app:titleTextColor="@android:color/white">

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

這里使用 android:fitsSystemWindows="true" 屬性解決內容試圖向上延伸的問題。實際上,也可以使用 android:paddingTop="@dimen/toolbar_padding_top" 的方式解決,toolbar_padding_top 間距為狀態欄高度,在大多數機器上狀態欄高度為 25dp,當然也可以通過代碼動態獲取狀態欄高度并設置到 Toolbar 的 paddingTop 屬性上。需要注意的是,這里要做兼容判斷,比如在 res/values/dimens.xml 中定義toolbar_padding_top 高度為 0dp,在 res/values-v19/dimens.xml 中為 25dp,確保兼容 Android 4.4 以下版本。

基本上,做到這些就能夠實現文章開頭處圖中的效果。值得注意的是,有時候如果想在 Android 5.0 及以上版本的系統中也做到全透明效果,或者說狀態欄與導航欄的顏色一致,還可以做進一步兼容處理,畢竟自 5.0 版本開始,系統對于狀態欄背景色的定制提供了更好的 API。如 res/values-v21/styles.xml 中定義:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="AppTheme" parent="BaseTheme">
        <item name="android:colorPrimary">@color/colorPrimary</item>
        <item name="android:colorPrimaryDark">@color/colorPrimary</item>
        <item name="android:colorAccent">@color/colorAccent</item>
    </style>

</resources>

說明一點,使用這種處理方式后,5.0 系統中應用的狀態欄背景色可隨意定制,同時與使用 <item name="android:windowTranslucentStatus">true</item> 樣式有所不同的是,該處理方式不會引起內容視圖的向上延伸,所以不需要在 layout 布局文件中額外添加 android:fitsSystemWindows="true" 屬性。當然,添加了也無所謂,畢竟還要兼容 4.4 到 5.0 之間的版本。

狀態欄白底黑字

前面我們說過,雖然說 4.4 版本開始,可以實現透明狀態欄效果,也就是可以通過各種手段實現修改狀態欄背景色,但是狀態欄圖標和文字的顏色默認為白色,這個是無法像 iOS 系統那樣,根據應用的整體色調動態修改。如果恰好 Toolbar 的背景色為白色,為了保持一致,將狀態欄背景色調為白色的話,就會與狀態欄的白色內容發生沖突,導致其內容無法凸顯,這個體驗肯定無法被用戶接受。

所以,遇見這種 Toolbar 或者說導航欄背景色為白色的情況,一般有兩種處理方式:第一種,不修改狀態欄背景色,通常默認為黑色背景白色內容;第二種,修改狀態欄背景色為淡黑色,這樣既能顯示狀態欄內容,又能與白色導航欄弱顯銜接,比如支付寶 App 就是這么做的:

像上圖這種處理方式較黑色狀態欄來說,相對緩和一些,那能不能做到修改狀態欄內容的顏色呢,比如白底黑字?大家知道,Android 系統是開源的,國內的各家手機廠商都做了一些自己的定制,像部分廠商定制的系統就提供了相應的 API 供開發人員做適配工作。比如,部分廠商就提供了相應的 API 來修改狀態欄內容顏色,實現狀態欄白底黑字效果,如圖:

具體做法就是,在代碼中判斷系統類型,與提供修改狀態內容顏色的系統匹配,使用其特定的 API 操作即可。目前開放這種定制 API 的系統已知有 MIUI 和 Flyme 系統,具體實現代碼可參考:

其實,在 Android 6.0(API 23)及更高的版本上,系統也開始提供了對應的 API 來實現淺色調背景的狀態欄效果,可將狀態欄圖標和文字內容改為黑色樣式,實現方式為:

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);
    getWindow().setStatusBarColor(Color.TRANSPARENT);
}

但是不知國內廠商在定制系統時是否對此有做處理,能否兼容這個 API ?不過,貌似微博 App 是這么做的,大家感興趣地不妨一試。

注意事項

除了上述 Toolbar 與 狀態欄在背景色上的銜接,App 中常見還有這樣一種設計,以微博個人主頁為例,如圖所示:

頁面頂部的圖片內容延伸至狀態欄中,這種做法其實就是單獨使用 <item name="android:windowTranslucentStatus">true</item> 樣式,不在 layout 布局文件中添加 android:fitsSystemWindows="true" 屬性即可。

還有一點,通常我們會在資源文件中定義不同版本的主題樣式,再在 <application> 標簽中統一設置,然后所有的 Activity 都能使用這個主題樣式。但存在這樣一種情況,Activity 由不同的 Fragment 組成,然后不同 Fragment 在狀態欄的呈現上有所不同,比如有的 Fragment 頂部使用 Toolbar 與狀態欄銜接,有的頂部直接使用圖片延伸至狀態欄上甚至不會用到 Toolbar,如圖所示:

由于 Fragment 是無法像 Activity 那樣在 AndroidManifest.xml 中單獨設置主題樣式的,所以這里可以這樣做:宿主 Activity 還是使用透明樣式,以滿足圖片延伸的 Fragment 頁面效果,其他使用 Toolbar 的 Fragment,在其 Layout 布局文件頂部單獨定義一個 View,讓其延伸至狀態欄,然后在代碼中根據不同版本系統設置其高度,4.4 版本以下設置該 View 高度為0,4.4 及以上版本設置為設備狀態欄高度,通過代碼獲取狀態高度的方式如下:

/**
 * 獲取狀態欄高度
 * @param activity
 * @return
 */
public static int getStatusBarHeight(Activity activity){
    Rect rect = new Rect();
    activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
    return rect.top==0 ? 60 : rect.top;
}

相關拓展

以上便是有關 Android 4.4 開始的狀態欄背景色相關知識,可以看出 4.4 、5.0 、6.0 版本作為三個分水嶺,根據需要做好相關適配工作即可。還有一種通過 setSystemUiVisibility() 方法設置狀態欄的方式,還能實現狀態欄的顯示與隱藏交互效果,具體可參考這篇文章:

GitHub 上對于 Android 4.4 版本開始的狀態欄背景色的處理有一個開源庫,感興趣地朋友也可借鑒參考一番,地址如下:

有關 Toolbar 替換 ActionBar 的使用,可以我之前總結的一篇文章,地址為:

 

來自:http://yifeng.studio/2017/02/19/android-statusbar/

 

 本文由用戶 hlim9135 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!