最近在開發中遇到一種個性化的需求,相似於QQ頂部的漸變狀態欄的實現,以下圖 android
首先咱們要了解在Android5.0之後,系統API提供直接設置StatusBar來改變狀態欄的顏色,然而在4.4上StatusBar變色的基本原理就是將StatusBar自己設置爲透明,而後在StatusBar的位置添加一個相同大小的View並上色。沒辦法,咱們要作的漸變顏色狀態欄就是要兼容上下版本的差別git
更多關於沉浸式狀態欄的瞭解可參考洪洋大神的文章github
Android 沉浸式狀態欄攻略 讓你的狀態欄變色吧bash
/** * 設置狀態欄顏色 * * @param activity 須要設置的activity * @param color 狀態欄顏色值 * @param statusBarAlpha 狀態欄透明度 */ public static void setColor(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.0以上版本 //設置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS屬性才能調用setStatusBarColor方法來設置狀態欄顏色 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); //設置FLAG_TRANSLUCENT_STATUS透明狀態欄 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //根據輸入的顏色和透明度顯示 activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha)); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //低版本 //添加透明狀態欄 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //獲取頂級視圖 ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); //獲取頂部的StatusBarView,自定義StatusBarView的Id(在resources中建立Id) View fakeStatusBarView = decorView.findViewById(R.id.statusbarutil_fake_status_bar_view); if (fakeStatusBarView != null) { if (fakeStatusBarView.getVisibility() == View.GONE) { fakeStatusBarView.setVisibility(View.VISIBLE); } //設置頂層顏色 fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); } else { //上述不符合,則建立一個View添加到頂級視圖中 decorView.addView(createStatusBarView(activity, color, statusBarAlpha)); } setRootView(activity); } } 複製代碼
/** * 計算狀態欄顏色 * * @param color color值 * @param alpha alpha值 * @return 最終的狀態欄顏色 */ private static int calculateStatusColor(@ColorInt int color, int alpha) { if (alpha == 0) { return color; } float a = 1 - alpha / 255f; int red = color >> 16 & 0xff; int green = color >> 8 & 0xff; int blue = color & 0xff; red = (int) (red * a + 0.5); green = (int) (green * a + 0.5); blue = (int) (blue * a + 0.5); return 0xff << 24 | red << 16 | green << 8 | blue; } 複製代碼
/** * 自定義View狀態欄 * * @param activity 須要設置的activity * @param color 狀態欄顏色值 * @param alpha 透明值 * @return 狀態欄矩形條 */ private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) { // 繪製一個和狀態欄同樣高的矩形 View statusBarView = new View(activity); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setLayoutParams(params); statusBarView.setBackgroundColor(calculateStatusColor(color, alpha)); //自定義的StatusBarView的Id statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID); return statusBarView; } 複製代碼
最後從新規劃佈局markdown
/** * 設置根佈局參數 */ private static void setRootView(Activity activity) { //ViewGroup容器存放UI組件 ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content); for (int i = 0, count = parent.getChildCount(); i < count; i++) { View childView = parent.getChildAt(i); if (childView instanceof ViewGroup) { childView.setFitsSystemWindows(true); ((ViewGroup) childView).setClipToPadding(true); } } } 複製代碼
由此純色狀態欄的基本配置就能夠了,只須要建立Utils工具類在Activity中調用便可,app
//設置純色狀態欄
StatusBarUtil.setColor(this, AppUtils.getColor(R.color.colorPrimary));
複製代碼
代碼以下工具
/** * 爲界面設置自定義透明View * * @param activity 須要設置的activity * @param statusBarAlpha 狀態欄透明度 * @param needOffsetView 須要向下偏移的 View public static void setTranslucentForWindow(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha, View needOffsetView) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { //5.0以上版本 setTransparentForWindow(activity); addTranslucentView(activity, statusBarAlpha); if (needOffsetView != null) { Object haveSetOffset = needOffsetView.getTag(TAG_KEY_HAVE_SET_OFFSET); if (haveSetOffset != null && (Boolean) haveSetOffset) { return; } ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams(); layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity), layoutParams.rightMargin, layoutParams.bottomMargin); needOffsetView.setTag(TAG_KEY_HAVE_SET_OFFSET, true); } } else { //低版本 //添加透明狀態欄 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //獲取頂級視圖 ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); //獲取頂部的StatusBarView,自定義id View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID); if (fakeStatusBarView != null) { if (fakeStatusBarView.getVisibility() == View.GONE) { fakeStatusBarView.setVisibility(View.VISIBLE); } //設置頂層顏色 fakeStatusBarView.setBackgroundResource(R.drawable.shape_gradient); } else { //上述不符合,則建立一個View添加到頂級視圖中 View statusBarView = new View(activity); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setLayoutParams(params); fakeStatusBarView.setBackgroundResource(R.drawable.shape_gradient); statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID); decorView.addView(statusBarView); } setRootView(activity); } } 複製代碼
/** * 獲取狀態欄高度 * * @param context context * @return 狀態欄高度 */ public static int getStatusBarHeight(Context context) { // 得到狀態欄高度 int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); return context.getResources().getDimensionPixelSize(resourceId); } 複製代碼
/** * 設置透明 */ public static void setTransparentForWindow(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { activity.getWindow().setStatusBarColor(Color.TRANSPARENT); activity.getWindow() .getDecorView() .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { activity.getWindow() .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } 複製代碼
/** * 添加半透明矩形條 * * @param activity 須要設置的 activity * @param statusBarAlpha 透明值 */ private static void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) { ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);//系統Id View fakeTranslucentView = contentView.findViewById(FAKE_TRANSLUCENT_VIEW_ID); if (fakeTranslucentView != null) { if (fakeTranslucentView.getVisibility() == View.GONE) { fakeTranslucentView.setVisibility(View.VISIBLE); } fakeTranslucentView.setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0)); } else { contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha)); } } 複製代碼
由此漸變顏色的狀態欄設置,只須要將toolbar做爲View傳入,調用以下oop
//設置漸變顏色狀態欄 StatusBarUtil.setTransparentForWindow(this, mToolbar); //佈局以下 <?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="wrap_content"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/shape_gradient" android:theme="@style/AppTheme.AppBarOverlay" app:elevation="@dimen/dp0"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/ToolbarPopupTheme" app:title="@string/main_toolbar_title_top" app:titleTextColor="@color/colorPrimary"> </android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> </LinearLayout> 複製代碼
至此,漸變色狀態欄的配置已經介紹徹底了ui