Android 修改狀態列和沉浸式佈局總結
阿新 • • 發佈:2019-01-02
不多說獻上工具類。
對於只想改變狀態列顏色的,只需要在Activity的setContentView之後呼叫。package com.yazhi1992.practice.immersion_status_bar; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.LinearLayout; public class StatusBarUtils { private Activity mActivity; //狀態列顏色 private int mColor = -1; //狀態列drawble private Drawable mDrawable; //是否是最外層佈局是 DrawerLayout 的側滑選單 private boolean mIsDrawerLayout; //是否包含 ActionBar private boolean mIsActionBar; //側滑選單頁面的內容檢視 private int mContentResourseIdInDrawer; public StatusBarUtils(Activity activity) { mActivity = activity; } public static StatusBarUtils with(Activity activity) { return new StatusBarUtils(activity); } public int getColor() { return mColor; } public StatusBarUtils setColor(int color) { mColor = color; return this; } public Drawable getDrawable() { return mDrawable; } public StatusBarUtils setDrawable(Drawable drawable) { mDrawable = drawable; return this; } public boolean isDrawerLayout() { return mIsDrawerLayout; } public boolean isActionBar() { return mIsActionBar; } public StatusBarUtils setIsActionBar(boolean actionBar) { mIsActionBar = actionBar; return this; } /** * 是否是最外層佈局為 DrawerLayout 的側滑選單 * * @param drawerLayout 是否最外層佈局為 DrawerLayout * @param contentId 內容檢視的 id * @return */ public StatusBarUtils setDrawerLayoutContentId(boolean drawerLayout, int contentId) { mIsDrawerLayout = drawerLayout; mContentResourseIdInDrawer = contentId; return this; } public void init() { fullScreen(mActivity); if (mColor != -1) { //設定了狀態列顏色 addStatusViewWithColor(mActivity, mColor); } if (mDrawable != null) { //設定了狀態列 drawble,例如漸變色 addStatusViewWithDrawble(mActivity, mDrawable); } if (isDrawerLayout()) { //未設定 fitsSystemWindows 且是側滑選單,需要設定 fitsSystemWindows 以解決 4.4 上側滑選單上方白條問題 fitsSystemWindows(mActivity); } if (isActionBar()) { //要增加內容檢視的 paddingTop,否則內容被 ActionBar 遮蓋 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content); rootView.setPadding(0, getStatusBarHeight(mActivity) + getActionBarHeight(mActivity), 0, 0); } } } /** * 去除 ActionBar 陰影 */ public StatusBarUtils clearActionBarShadow() { if (Build.VERSION.SDK_INT >= 21) { ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar(); if (supportActionBar != null) { supportActionBar.setElevation(0); } } return this; } /** * 設定頁面最外層佈局 FitsSystemWindows 屬性 * * @param activity */ private void fitsSystemWindows(Activity activity) { ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content); View parentView = contentFrameLayout.getChildAt(0); if (parentView != null && Build.VERSION.SDK_INT >= 14) { parentView.setFitsSystemWindows(true); //佈局預留狀態列高度的 padding if (parentView instanceof DrawerLayout) { DrawerLayout drawer = (DrawerLayout) parentView; //將主頁面頂部延伸至status bar;雖預設為false,但經測試,DrawerLayout需顯示設定 drawer.setClipToPadding(false); } } } /** * 利用反射獲取狀態列高度 * * @return */ public static int getStatusBarHeight(Activity activity) { int result = 0; //獲取狀態列高度的資源id int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = activity.getResources().getDimensionPixelSize(resourceId); } Log.e("getStatusBarHeight", result + ""); return result; } /** * 獲得 ActionBar 的高度 * * @param context * @return */ public static int getActionBarHeight(Context context) { int result = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { TypedValue tv = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); } return result; } /** * 新增狀態列佔位檢視 * * @param activity */ private void addStatusViewWithColor(Activity activity, int color) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (isDrawerLayout()) { //要在內容佈局增加狀態列,否則會蓋在側滑選單上 ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content); //DrawerLayout 則需要在第一個子檢視即內容試圖中新增padding View parentView = rootView.getChildAt(0); LinearLayout linearLayout = new LinearLayout(activity); linearLayout.setOrientation(LinearLayout.VERTICAL); View statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setBackgroundColor(color); //新增佔位狀態列到線性佈局中 linearLayout.addView(statusBarView, lp); //側滑選單 DrawerLayout drawer = (DrawerLayout) parentView; //內容檢視 View content = activity.findViewById(mContentResourseIdInDrawer); //將內容檢視從 DrawerLayout 中移除 drawer.removeView(content); //新增內容檢視 linearLayout.addView(content, content.getLayoutParams()); //將帶有佔位狀態列的新的內容檢視設定給 DrawerLayout drawer.addView(linearLayout, 0); } else { //設定 paddingTop ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content); rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //直接設定狀態列顏色 activity.getWindow().setStatusBarColor(color); } else { //增加佔位狀態列 ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView(); View statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setBackgroundColor(color); decorView.addView(statusBarView, lp); } } } } /** * 新增狀態列佔位檢視 * * @param activity */ private void addStatusViewWithDrawble(Activity activity, Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //佔位狀態列 View statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { statusBarView.setBackground(drawable); } else { statusBarView.setBackgroundDrawable(drawable); } if (isDrawerLayout()) { //要在內容佈局增加狀態列,否則會蓋在側滑選單上 ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content); //DrawerLayout 則需要在第一個子檢視即內容試圖中新增padding View parentView = rootView.getChildAt(0); LinearLayout linearLayout = new LinearLayout(activity); linearLayout.setOrientation(LinearLayout.VERTICAL); //新增佔位狀態列到線性佈局中 linearLayout.addView(statusBarView, lp); //側滑選單 DrawerLayout drawer = (DrawerLayout) parentView; //內容檢視 View content = activity.findViewById(mContentResourseIdInDrawer); //將內容檢視從 DrawerLayout 中移除 drawer.removeView(content); //新增內容檢視 linearLayout.addView(content, content.getLayoutParams()); //將帶有佔位狀態列的新的內容檢視設定給 DrawerLayout drawer.addView(linearLayout, 0); } else { //增加佔位狀態列,並增加狀態列高度的 paddingTop ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView(); decorView.addView(statusBarView, lp); //設定 paddingTop ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content); rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0); } } } /** * 通過設定全屏,設定狀態列透明 * * @param activity */ private void fullScreen(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.x開始需要把顏色設定透明,否則導航欄會呈現系統預設的淺灰色 Window window = activity.getWindow(); View decorView = window.getDecorView(); //兩個 flag 要結合使用,表示讓應用的主體內容佔用系統狀態列的空間 int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); decorView.setSystemUiVisibility(option); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); //導航欄顏色也可以正常設定 // window.setNavigationBarColor(Color.TRANSPARENT); } else { Window window = activity.getWindow(); WindowManager.LayoutParams attributes = window.getAttributes(); int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; attributes.flags |= flagTranslucentStatus; // attributes.flags |= flagTranslucentNavigation; window.setAttributes(attributes); } } } /** * 通過設定全屏,設定狀態列透明 導航欄黑色 * * @param activity */ public static void setStatusTransparent(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window window = activity.getWindow(); WindowManager.LayoutParams attributes = window.getAttributes(); int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; // attributes.flags |= flagTranslucentStatus; attributes.flags |= flagTranslucentNavigation; window.setAttributes(attributes); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); window.setNavigationBarColor(Color.TRANSPARENT); } else { Window window = activity.getWindow(); WindowManager.LayoutParams attributes = window.getAttributes(); int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; attributes.flags |= flagTranslucentStatus; attributes.flags |= flagTranslucentNavigation; window.setAttributes(attributes); } } } }
StatusBarUtils.with(this)
.setColor(getResources().getColor(R.color.blue))
.init();
至於佈局上部分是圖片或者背景是圖片的,需要沉浸式佈局,也非常的簡單,效果如下圖所示。StatusBarUtils.with(this)
.init();