Android改變狀態列顏色及沉浸式模式的封裝
阿新 • • 發佈:2019-01-22
talk is cheap,show me your code.
/** * Author: zhangbo * Data:2018/9/7 * TODO: */ public class StatusBarUtil { /** *設定狀態列顏色 */ public static void setStatusBarColor(Activity activity, int color){ //5.0以上呼叫window的setStatusBarColor可設定狀態列顏色 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); activity.getWindow().setStatusBarColor(color); /** 6.0需要用如下程式碼處理相容,不然設定的狀態列顏色會與內容檢視有明顯的分界線 參考StatusBarCompat庫的原始碼**/ /*View v = activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT); if (v != null) { v.setForeground((Drawable)null); }*/ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //此處設定狀態列透明後content檢視就用鋪滿全屏佔用狀態列的空間 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //然後建立一個和狀態列高度一樣的View新增到根檢視(FrameLayout)中 ViewGroup decorView = (ViewGroup) activity.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); //此處等同於通過程式碼設定xml佈局檔案中的根檢視android:fitsSystemWindows="true" //效果就是讓xml佈局的檢視也就是contentView不佔用狀態列空間,也就是上面建立的statusBarView鋪在了原狀態列的位置,間接實現了改變狀態列顏色的效果 //注意的是setStatusBarColor函式需要在Activity的setContentView之後呼叫,否則下面的程式碼設定fitsSystemWindows屬性無效 ViewGroup contentView = (ViewGroup)activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT); View childView = contentView.getChildAt(0);////此處的childView就是當前activity的xml佈局檔案中的根檢視 if (childView != null) { childView.setFitsSystemWindows(true); //其實通過手動設定佈局檔案根檢視的PaddingTop增高和狀態列等高的高度,效果是一樣的(我真是個天才~~) //view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context), //view.getPaddingRight(), view.getPaddingBottom()); } } } /** * 關於沉浸式模式,其實也就是讓內容內容檢視佔用狀態列空間全屏顯示,5.0以上有系統API支援呼叫相關函式即可 * 至於4.4以上 一句程式碼就能實現全屏顯示 不多BB 不嫌麻煩可以參考上面的函式手動設定fitsSystemWindows為false來 * 保證內容佈局為全屏顯示。 **/ public static void immersiveStatusBar(Window window) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); //完全的沉浸式模式 // int immersiveMode = View.SYSTEM_UI_FLAG_LAYOUT_STABLE // | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN // | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // | View.SYSTEM_UI_FLAG_FULLSCREEN // | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; int systemUiVisibility = window.getDecorView().getSystemUiVisibility(); systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; window.getDecorView().setSystemUiVisibility(systemUiVisibility); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } } /** * 獲取狀態列的高度 */ public static int getStatusBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } /** 增加View的paddingTop,增加的值為狀態列高度 */ public static void setPadding(Context context, View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context), view.getPaddingRight(), view.getPaddingBottom()); } } /****************************最後附上郭霖大神的文章中關於沉浸式需求的解決方案*****************************************/ /** * 沉浸式模式的三種解決方案,參考文章:https://blog.csdn.net/guolin_blog/article/details/51763825 * @param activity */ public static void immersive(Activity activity){ /**① 純粹設定decorView全屏顯示,狀態列會被完全隱藏,支援最低Android4.1**/ // View decorView = activity.getWindow().getDecorView(); // int option = View.SYSTEM_UI_FLAG_FULLSCREEN; // decorView.setSystemUiVisibility(option); //官方建議ActionBar不應獨立於狀態列顯示,這裡隱藏,如果使用的是NoActionBar的主題可以不管 // ActionBar actionBar = getSupportActionBar(); // actionBar.hide(); /**② 兩個Flag必須要結合在一起使用,表示會讓應用的主體內容佔用系統狀態列的空間,並設定狀態列背景色為透明 * 呈現的效果就是內容佈局全屏顯示,狀態列內容覆蓋在螢幕內容上面,但背景色為透明**/ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);//這個flag不加 三星手機設定狀態列顏色無效 // View decorView = activity.getWindow().getDecorView(); int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; decorView.setSystemUiVisibility(option); activity.getWindow().setStatusBarColor(Color.TRANSPARENT); //setStatusBarColor為5.0新增 } // ActionBar actionBar = getSupportActionBar();//同上 // actionBar.hide(); /**③真正的完全沉浸式模式,需要在Activity的onWindowFocusChanged函式中複寫,效果為預設全屏顯示內容,當點選屏幕後 * 狀態列和導航欄才會顯示出來,一段時間螢幕無感應後繼續隱藏,一般在視訊和遊戲類專案中才會需要這種沉浸式體驗,方案②中的效果就能滿足其他的所謂的“沉浸式”需求 **/ // @Override // public void onWindowFocusChanged(boolean hasFocus) { // super.onWindowFocusChanged(hasFocus); // if (hasFocus && Build.VERSION.SDK_INT >= 19) { // View decorView = getWindow().getDecorView(); // decorView.setSystemUiVisibility( // View.SYSTEM_UI_FLAG_LAYOUT_STABLE // | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN // | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // | View.SYSTEM_UI_FLAG_FULLSCREEN // | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); // } // } } }
原始碼參考: 2個都是gayhub上很火的開源框架,實現原理都一樣,但都有點小坑:
compile ‘com.githang:status-bar-compat:0.7’ //這個只有改變狀態列顏色的函式,沒有設定全屏沉浸式的功能
compile ‘com.jaeger.statusbaruitl:library:1.3.5’ //專案中compile方式依賴的v4 v7包會與這個lib衝突