前言
很多UI設計都要求修改狀態欄的一些顏色、字體顏色、沉浸式等等效果,這篇博客就重點整理所有狀態欄開發技術點。
關於國內手機廠商的適配問題
我目前已經不太關心適配問題了,之前的Android版本因為google的問題導致狀態欄上嚴重跟不上時代,各種效果無法實現,導致各個廠商都自己實現狀態欄碎片化很嚴重,讓兼容問題無比復雜,但是在Android8.0后。google已經完善了狀態欄最后一塊短板,所以大部分廠商已經放棄了自己造輪子的行為,加入了google原生的實現。且目前國內的設備普遍都是Android8.0以上了。之前的各色狀態欄兼容工具類已經意義不大了,所以回歸到了正道上,學習google原生折騰狀態欄的方法。
改變colorPrimaryDark顏色, 從而改變狀態欄顏色
在app創建后在styles文件里的AppTheme(這個是默認主題,如果你修改為了其他你自定義的主題,以你的主題為標准)主題下colorPrimaryDark屬性,它是作用於狀態欄的顏色值,參考下圖了解每一個屬性作用域:
改變colorPrimaryDark從而改變全局App狀態欄顏色
修改colorPrimaryDark改變狀態欄顏色,這是最簡單的方式,可以把全局App的每個頁面的狀態欄顏色都修改成指定顏色,代碼如下:
styles.xml
這里將狀態欄修改成黃色
<!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">#FF9800</item> <!--修改的黃色顏色值,這里只是舉例。實際項目還是把顏色值老老實實地放在color文件里--> <item name="colorAccent">@color/colorAccent</item> </style>
注意,這個主題要設置成app全局主題,在AndroidManifest里設置。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yt.modeldemo"> <application android:allowBackup="true" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <!--在這里設置全局主題-->
效果圖:
修改colorPrimaryDark,改變某一個Activity的狀態欄顏色
一個app全局只使用一種狀態欄顏色,這只是一個美好的願望。 實際項目十分蛋疼,各種activity都需要各種顏色的狀態欄。我們可以創建一個新的主題改變colorPrimaryDark顏色后,給這個activity使用。代碼如下:
styles.xml
<!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">#FF9800</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="MainActivityTheme" parent="AppTheme"> <!--其他屬性的顏色,我們依然需要使用全局AppTheme,所以這里直接引用它--> <item name="colorPrimaryDark">#2196F3</item> <!--修改這MainActivity需要使用的狀態欄顏色--> </style>
AndroidManifest.xml
找到需要設置的activity,將主題設置給它。
<activity android:name=".MainActivity" android:theme="@style/MainActivityTheme"> <!--設置這個activity的主題--> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
在activity里:
當然除了在AndroidManifest.xml里設置,我們還可以直接在代碼了里直接設置這個主題。請注意!代碼里設置主題一定要在 setContentView(R.layout.activity_main); 方法前面。(喜歡搞BaseActivity封裝setContentView的同學注意了!你們這就是脫褲子放屁多此一舉,反而在會影響別人設置setTheme,深刻了解什么是過度封裝,什么代碼統一一個地方修改全局,那也得看看是什么形式的封裝,google直接在創建Activity的時候都幫你寫好了,你這么厲害怎么不去google?)
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.MainActivityTheme);//設置主題,一定要在setContentView前面 setContentView(R.layout.activity_main); }
效果圖:
setStatusBarColor方法改變狀態欄顏色
此方法是Android 5.0 后提供的
代碼:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getWindow().setStatusBarColor(Color.RED); //略....
效果圖:
切換狀態欄字體與圖標顏色模式
說是切換顏色,其實Android只有2種模式,一種是深色模式,一種是高亮模式。Android的狀態欄字體與小圖標顏色是不允許自定義顏色的。提供這兩種模式是希望用戶可以在深色與亮色模式下都能看清楚狀態欄內容。
白底黑字的高亮模式
代碼:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setStatusBarColor(Color.WHITE);/*設置狀態欄背景顏色為白色*/ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//白低黑字的高亮模式 setContentView(R.layout.activity_main); //略....
效果圖:
默認的黑低白字的深色模式
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setStatusBarColor(Color.BLACK);/*設置狀態欄背景顏色為黑色*/ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);//STABLE為穩固的意思,其實就是默認模式 setContentView(R.layout.activity_main); //略....
效果圖:
在style Theme里設置
這個需要API 23 (Android 6.0)
<item name="android:windowLightStatusBar">true</item>
隱藏與顯示狀態欄
有兩種方式
第一種,設置Window flag形式,讓window全屏顯示,達到隱藏狀態欄的目的
這種方式是Android3.0以前隱藏狀態欄的方式,目前google應該不希望你用這種方式控制狀態欄,這只是控制window時達到的一種效果。請注意,使用這個方式可能會影響輸入盤的自動調整功能,所以非必要不應該使用這種方式隱藏狀態欄。
// 隱藏狀態欄 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // 顯示狀態欄 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
隱藏效果圖:
第二種,控制系統UI setSystemUiVisibility 隱藏或者顯示狀態欄
這種應該是google的推薦方式。是Android4.1后實現的方式
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);//隱藏狀態欄 getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);//顯示狀態欄 getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);//狀態欄圖標低調模式
低調模式效果圖:
自保留電量並且淡化電量圖標,其他圖標全部隱藏
沉浸式狀態欄
上面只改改狀態欄的顏色,有時候也無法滿足UI設計師們希望掌握狀態欄的野心。有時候會提供一張圖片,希望讓你將圖片成為狀態欄的背景配合App當前主題,這種狀態欄就是沉浸式狀態欄。這部分可能要涉及到一些標題欄的知識。
因為沉浸式狀態欄欄一般就包含了自定義標題欄,因為我們需要自定義一個能設置背景圖片的標題欄(或者你干脆沒有標題欄),所以需要新增或者修改創建一個沒有標題欄的主題:
隱藏標題欄的部分可以參考我另一篇博客:https://www.cnblogs.com/guanxinjing/p/13042584.html
styles.xml
<style name="NotTitleAppTheme" parent="AppTheme"> <item name="windowNoTitle">true</item> </style>
將這個主題導入,需要實現沉浸式狀態欄的Activity
AndroidManifest.xml
<activity android:name=".MainActivity" android:theme="@style/NotTitleAppTheme"> <!--設置這個沒有標題欄的主題--> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
在這個Activity的布局里添加,我們自己的Toolbar標題欄,如果你沒有需要標題欄就可以直接放一個ImageView進去
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:background="@android:color/white" tools:context=".MainActivity"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@mipmap/ic_image" android:fitsSystemWindows="true" app:layout_constraintTop_toTopOf="parent" app:title="標題" app:titleTextColor="@android:color/white"> </androidx.appcompat.widget.Toolbar> <Button android:id="@+id/add_count_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Hello world" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" /> </androidx.constraintlayout.widget.ConstraintLayout>
請注意,這里使用了一個 android:fitsSystemWindows="true" 屬性,如果是你的是一張圖片的ImageView也需要添加,這樣它會自動幫我們在標題欄里增加狀態欄的高度。
在Activity的代碼里設置狀態欄與添加Toolbar
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);/*讓布局可以全屏,延展到狀態欄里*/ getWindow().setStatusBarColor(Color.TRANSPARENT);/*透明狀態欄*/ //略...
請注意,這里設置的 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 屬性與上面的狀態欄隱藏是不一樣的,這里只是讓我們的布局可以延展到狀態欄里,讓我們布局成為狀態欄的一部分,所以叫Layout fullscreen 布局全屏。
效果圖:
取消沉浸式
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//或者設置SYSTEM_UI_FLAG_LAYOUT_STABLE
在沉浸式狀態欄下修改字體模式
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setStatusBarColor(Color.TRANSPARENT); /** * 在SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 布局全局情況下 在增加 SYSTEM_UI_FLAG_LAYOUT_STABLE 高亮模式 或者 SYSTEM_UI_FLAG_LAYOUT_STABLE 默認的深色模式 */ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); setContentView(R.layout.activity_main); //略....
獲取狀態欄高度
/** * 獲取狀態欄高度 * @param context * @return */ public static int getStatusBarHeight(Context context) { Resources resources = context.getResources(); int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); int height = resources.getDimensionPixelSize(resourceId); return height; }
End