Android UI體驗之全屏沉浸式透明狀態列效果

總李寫程式碼發表於2017-01-06

前言:

   Android 4.4之後谷歌提供了沉浸式全屏體驗, 在沉浸式全屏模式下, 狀態列、 虛擬按鍵動態隱藏, 應用可以使用完整的螢幕空間, 按照 Google 的說法, 給使用者一種 身臨其境 的體驗。而Android 5.0之後谷歌又提出了 ColorPalette 的概念,讓開發者可以自己設定系統區域的顏色,使整個 App 的顏色風格和系統的顏色風格保持統一。今天學習總結一下如何實現Android 4.4以上全屏沉浸式透明狀態列效果。先看下預期效果:

 首先現分清楚哪部分是狀態列,哪部分是導航欄

狀態列StatusBar如下

導航欄NavigationBar如下

如何實現?

 1.)首先實現全屏

 第一種:繼承主題特定主題

 在Android API 19以上可以使用****.TranslucentDecor***有關的主題,自帶相應半透明效果,Theme.Holo.NoActionBar.TranslucentDecor和Theme.Holo.Light.NoActionBar.TranslucentDecor兩種主題為新增加的,所以要新建values-v19資料夾並建立styles檔案新增如下程式碼

   <style name="AppBaseTheme" parent="android:Theme.Holo.Light.NoActionBar.TranslucentDecor">
        <!-- Customize your theme here. -->
  </style>

第二種:在activity中採用程式碼的方式

Android 4.4以上可以新增如下程式碼

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//透明狀態列
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明導航欄
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}

Android 5.0 以上也可以使用下面的程式碼實現全屏

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
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);
}

全屏效果

不難發現此時狀態列佔有的位置消失,和app的佈局疊在一起了,接下來解決這個問題

2.)解決狀態列佔位問題

第一種:主題新增如下設定

<item name="android:fitsSystemWindows">true</item>

第二種:activity layout根目錄新增下面程式碼

android:fitsSystemWindows="true"

第三種:通過Java程式碼設定

rootview.setFitsSystemWindows(true);

fitsSystemWindows只作用在sdk>=19的系統上就是高於4.4的系統,這個屬性可以給任何view設定,只要設定了這個屬性此view的所有padding屬性失效.只有在設定了透明狀態列(StatusBar)或者導航欄(NavigationBar)此屬性才會生效,

如果上述設定了狀態列和導航欄為透明的話,相當於對該View自動新增一個值等於狀態列高度的paddingTop,和等於導航欄高度的paddingBottom,效果如下

 3.)狀態列導航欄設定背景色

4.4以上的可以採用修改contentView的背景色,或者動態新增一個view到contentView上

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //透明狀態列
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //透明導航欄
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            //設定contentview為fitsSystemWindows
            ViewGroup contentView = (ViewGroup) findViewById(android.R.id.content);
            View childAt = contentView.getChildAt(0);
            if (childAt != null) {
                childAt.setFitsSystemWindows(true);
            }
            //給statusbar著色
            View view = new View(this);
            view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(this)));
            view.setBackgroundColor(color);
            contentView.addView(view);
        }

動態獲取StatusBarHeight函式如下

    /**
     * 獲取狀態列高度
     *
     * @param context context
     * @return 狀態列高度
     */
    private static int getStatusBarHeight(Context context) {
        // 獲得狀態列高度
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        return context.getResources().getDimensionPixelSize(resourceId);
    }

動態獲取NavigationBarHeight函式如下

    /**
     * 獲取導航欄高度
     *
     * @param context context
     * @return 導航欄高度
     */
    public static int getNavigationBarHeight(Context context) {
        int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        return context.getResources().getDimensionPixelSize(resourceId);
    }

然後Android5.0以上谷歌提供了新的api可以更新狀態列和導航欄的背景色

   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            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);
            //設定導航欄顏色
            window.setNavigationBarColor(color);
            ViewGroup contentView = ((ViewGroup) findViewById(android.R.id.content));
            View childAt = contentView.getChildAt(0);
            if (childAt != null) {
                childAt.setFitsSystemWindows(true);
            }
//            contentView.setPadding(0, getStatusBarHeight(this), 0, 0);
        }

這樣總體效果就實現了

4.)貼出整體java程式碼實現方式

    private void initWindows() {
        Window window = getWindow();
        int color = getResources().getColor(android.R.color.holo_blue_light);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            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);
            //設定導航欄顏色
            window.setNavigationBarColor(color);
            ViewGroup contentView = ((ViewGroup) findViewById(android.R.id.content));
            View childAt = contentView.getChildAt(0);
            if (childAt != null) {
                childAt.setFitsSystemWindows(true);
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //透明狀態列
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //透明導航欄
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            //設定contentview為fitsSystemWindows
            ViewGroup contentView = (ViewGroup) findViewById(android.R.id.content);
            View childAt = contentView.getChildAt(0);
            if (childAt != null) {
                childAt.setFitsSystemWindows(true);
            }
            //給statusbar著色
            View view = new View(this);
            view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(this)));
            view.setBackgroundColor(color);
            contentView.addView(view);
        }
    }

總結:

 我這裡為了更加明顯的顯示效果所以狀態列背景色和標題欄顏色不一致,在實際的開發中一般情況下我們都會設定成統一的顏色,在視覺上感覺整個頁面更加統一,讓使用者真正沉浸在app中。

相關文章