1. 程式人生 > >Android改變狀態列顏色及沉浸式模式的封裝

Android改變狀態列顏色及沉浸式模式的封裝

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衝突