關於Android4.4以後沉浸式自定義狀態欄實現

作爲Android開發,在解決4.4沉浸式狀態欄遇到挺多問題的,這裏列出我自己的解決方案,僅供參考。
首先是主題的配置:
默認主題 styles配置:

<style name="AppTheme" parent="android:Theme.Light">
        <item name="windowNoTitle">true</item>
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

v19以及以上版本主題 styles配置:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>

        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

這裏屬性windowTranslucentStatus和windowTranslucentNavigation很重要,不然自定義的沉浸式狀態欄無效。

然後就是佈局文件中的屬性:

android:fitsSystemWindows="true"

該屬性如果不設置的話,那麼就需要完全自定義StatusBar和NavigationBar。

這裏我的解決方案是自定義一個BaseActivity類。裏邊預設一個沉浸式菜單樣式。列出部分代碼。
初始化一個系統狀態欄。

 /**
     * @param color 頂部狀態欄顏色
     * @param alpha 頂部狀態欄透明度
     */
    public void initSystemBar(int color, float alpha) {
        if (mTintManager == null) {
            mTintManager = new SystemBarTintManager(this);
            setTranslucentStatus(true);
            try {
                Field field = mTintManager.getClass().getDeclaredField("mNavBarAvailable");
                field.setAccessible(true);
                Object obj = field.get(mTintManager);
                mNavBarAvailable = obj instanceof Boolean ? (Boolean) obj : false;
                Field field1 = mTintManager.getClass().getDeclaredField("mNavBarTintView");
                field1.setAccessible(true);
                Object view = field1.get(mTintManager);
                mNavBarTintView = view instanceof View ? (View) view : null;
                if(mNavBarTintView!=null){
                    mNavBarTintView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                        @Override
                        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                            if(navBarLayoutChangeListener!=null)
                                navBarLayoutChangeListener.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
                        }
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mTintManager.setStatusBarTintEnabled(true);
        mTintManager.setNavigationBarTintEnabled(true);
        mTintManager.setStatusBarAlpha(alpha);
        mTintManager.setStatusBarTintColor(getResources().getColor(color));
        mTintManager.setNavigationBarAlpha(mNavBarAvailable && navVisiablity == View.VISIBLE ? 1.0f : 0.0f);
        mTintManager.setNavigationBarTintColor(getResources().getColor(R.color.colorPrimaryDark));//底部狀態欄默認顏色
    }

順便列出對於部分手機底部狀態欄可隱藏解決方法。如果有比較好的方法可以告訴我。我這裏主要是寫一個死循環定期去檢測底部狀態欄(應該不是很好),所以做了一定的處理,獲取底部狀態欄是否可用,如果不可用就不啓動死循環檢測。雖然網上有很多方法說去檢測狀態欄可見性,但是好像沒什麼效果。
在onResume方法啓動檢測。

 @Override
    protected void onResume() {
        super.onResume();
        initSystemBar(R.color.colorPrimaryDark);
        startNavBarTask();
    }

在onPause方法暫停檢測。

 @Override
    protected void onPause() {
        super.onPause();
        onPauseNaBarTask();
    }

在onDestroy方法停止檢測。

 @Override
    protected void onDestroy() {
        super.onDestroy();
        cancelNaBarTask();
    }

對於自定義頂部狀態欄,我們只需要根據Android手機版本確定是否展示即可:

//根據版本確定是否顯示StatusBar狀態欄 系統版本大於等於19才顯示
        statusBar.setVisibility(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? View.VISIBLE : View.GONE);

對於自定義底部狀態欄添加監聽:(該方法是在BaseActivity中定義的,就是剛剛那個檢測任務回調,當底部狀態欄改變時)

 //添加NavigationBar可見性監聽
        addNavBarVisiableChangeListener(new NavBarVisiableChangeListener() {
            @Override
            public void onNavBarVisiableChange(View navBarView, int visibility) {
                if (navigationBar != null) {
                    navigationBar.setVisibility(visibility == View.VISIBLE ? View.VISIBLE : View.GONE);
                }
            }
        });

當然這裏還做了自定義底部狀態欄高度檢測,主要是有些手機狀態欄高度不同,必須要做(網上有很多方法,但是都不太靠譜,這裏我通過監聽底部狀態視圖佈局變化來實現的)

//設置NavigationBar佈局監聽,這裏主要是因爲系統的狀態欄不同手機高度不同,所以要監聽
        setNavBarLayoutChangeListener(new NavBarLayoutChangeListener() {
            @Override
            public void onLayoutChange(View navBarView, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                int navHeight = navBarView.getMeasuredHeight();
                int height = navigationBar.getMeasuredHeight();
                if (navHeight > 0 && navHeight != height) {
                    ViewGroup.LayoutParams lp = navigationBar.getLayoutParams();
                    if (lp != null)
                        lp.height = navHeight;
                }
            }
        });

差不多核心代碼都列出來,同時可以參考我自己做的一個demo。
github地址:https://github.com/ttarfall/StatusBarDemo.git

發佈了37 篇原創文章 · 獲贊 26 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章