Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android沉浸式狀態欄攻略

Android沉浸式狀態欄攻略

編輯:關於Android編程

前言

這裡不討論[沉浸式]這個詞用得好不好, 大家聽得懂就行. 這篇文章主要是我在實際項目中的一些經驗, 整理出來和大家分享, 歡迎探討. 由於實習一直是996, 沒時間做總結, 今天突然覺得這樣的工作讓我都忘了生活了, 是時候做個了斷了. 寫這篇文章的時候已經是23:44, 來不及貼一些demo, 但是這裡的代碼都是曾經的項目中摘出來的, 是可以運行的, 但我現在沒有真的執行一遍. 注意所有的代碼都只在android 4.4及以上有效.

考慮

根據實際項目的不同, 可能選擇的沉浸式實現策略也會有所不同.

傳統純色actionbar

如果你的app使用的是遵循android規范的actionbar或者有一個純色layout放在屏幕頂部, 那麼這裡有一個入侵較小的方案, 這個方案的實現方式是參考的開源項目SystemBarTint.
讓你的activity繼承一個BaseActivity, 在BaseActivity裡面重寫onPostCreate

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)  {
        ImmerseHelper.setSystemBarTransparent(this);
        }
    }

重點在ImmerseHelper這個類裡, 先貼代碼再講解.

public class ImmerseHelper {
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static void setSystemBarTransparent(Activity paramActivity)
    {
        Window window = paramActivity.getWindow();
        WindowManager.LayoutParams layoutParams = window.getAttributes();
        layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        window.setAttributes(layoutParams);
        hackStatusBarTransparent(paramActivity);
        setContentPadding(paramActivity);
    }

    public static void hackStatusBarTransparent(Activity paramActivity) {
        ViewGroup localViewGroup = (ViewGroup) paramActivity.getWindow().getDecorView()
                .findViewById(android.R.id.content);
        View colorview = new View(paramActivity);
        colorview.setBackgroundResource(R.color.statusbar_color);
        localViewGroup.addView(colorview, ViewGroup.LayoutParams.MATCH_PARENT,
                ImmerseHelper.getStatusBarHeight(paramActivity));
    }

    public static void setContentPadding(Activity activity) {
        ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0)
            .setPadding(0, ImmerseHelper.getStatusBarHeight(activity) 
                    + ImmerseHelper.getActionBarHeight(activity), 0, 0);
    }

    /**
     * 獲取狀態欄高度, 單位px
     * @param context
     * @return
     */
    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;
    }

    /**
     * 獲取actionbar高度, 單位px
     * @param context
     * @return
     */
    public static int getActionBarHeight(Context context)
    {
        TypedValue localTypedValue = new TypedValue();
        if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, localTypedValue, true)) {
            return TypedValue.complexToDimensionPixelSize(localTypedValue.data, context.getResources().getDisplayMetrics());
        }
        return 0;
    }
}

簡單來說就是在postCreate時對activity做手腳, 這樣組內其他開發者幾乎感受不到變化, 只需要將activity的基類指定成BaseActivity就好
ImmerseHelper這個類主要做了三件事
- 將window的FLAG_TRANSLUCENT_STATUS標志打開
- 給某個View中添加了一個與狀態欄大小完全相同的純色塊
- 給activity的根View設置paddingTop
FLAG_TRANSLUCENT_STATUS這個標志打開之後, 狀態欄就透明了, 同時我們的activity的主體布局, 也就是setContentView傳入的那個布局, 會頂到屏幕最上方, 被狀態欄蓋住一部分, 注意actionbar是不會受影響的. 所以我們在第三步給activity的根view設了paddingTop, 高度是狀態欄的高度加上actionbar的高度, 這樣activity中的內容才會回到之前的正常位置. 但此時狀態欄下方透明了, 所以我們給某個View中添加了一個與狀態欄大小完全相同的色塊, 顏色和actionbar一致, 這樣就有了沉浸式效果.
當然這裡的效果是狀態欄下面有一層半透明黑底, 之後才是我們添加的view, 所以不用擔心看不到狀態文字, 在4.4上只能做到這個效果, 5.0上可以讓狀態欄底部完全透明, 這個等會兒說.
不過光有實現不行, 還需要知道為什麼我們要這麼做

原理

先看一下hierarchy view的截圖

hierarchy

我們getDecorView拿到的是最左邊的DecorView, 而setContentView影響的是id/content那個view的直接子view, 和id/content平級的view是actionbar.
activity.getWindow().getDecZ喎?/kf/ware/vc/" target="_blank" class="keylink">vclZpZXcoKS5maW5kVmlld0J5SWQoYW5kcm9pZC5SLmlkLmNvbnRlbnQpOzwvY29kZT7V4r7kxMO1vbXEysdpZC9jb250ZW501eK49nZpZXcsIM7Sw8fP8sbk1tDM7bzT0ru49rS/yat2aWV3LCDTydPatPK/qsHLRkxBR19UUkFOU0xVQ0VOVF9TVEFUVVMsINXiuPa0v8mrdmlld77N1rG907al1NrX7snPw+YsINKyvs3Kx9e0zKzAuLiyuMe1xLXYt70uPGJyIC8+DQpTeXN0ZW1CYXJUaW501tCyorfHysfP8mlkL2NvbnRlbnTW0GFkZFZpZXcsILb4ysfWsb3Tz/I8Y29kZT5nZXREZWNvclZpZXcoKTwvY29kZT7W0GFkZFZpZXcsILb4U3dpcGVCYWNrTGF5b3V01PLKx9TaRGVjb3JWaWV3us3L+7XE19NWaWV31q685LLlyOvX1Ly6tcRsYXlvdXQsIM/gtbHT2r3Zs9bBy0RlY29yVmlld7XE19NWaWV3LCDL+dLUyOe5+82syrHKudPD1eLBvbj2v6rUtM/uxL+yu7zT0N64xCwg0qrDtLustq+3tbvYu67X37XEysfXtMyswLgsINKqw7TXtMyswLjLusHRLiDI57n7z/HO0tXiw7TQtCwgvs2yu7vhus1Td2lwZUJhY2tMYXlvdXSz5c27LjwvcD4NCjxoMiBpZD0="非傳統">非傳統

完全頂在頂部

如果你要做到向上圖這樣, 圖片完全頂在頂部, 那麼就不建議使用actionbar了, 同時也不需要setContentPadding這步. 有時這樣會導致某些頁面的內容過分偏上, 這個時候建議用一個dimen, 在正常情況下是0dp, v19及以上時是24dp, 這也是狀態欄高度, 哪些頁面要隔開狀態欄, 就用這個dimen做marginTop, 或者include一個高度為這個dimen的layout.
這樣子的入侵比較強, 做新的頁面需要時刻注意和狀態欄是否需要保持距離, 很容易忘記, 不過也不算什麼困難, 畢竟一運行就看出來了.

Lolipop+特有方法

上面說的都是api level 19的方法, 唯一的缺陷是狀態欄並非完全透明, 而是底部有個半透明的黑條, 在api level 21上, 我們可以去掉這個半透明黑條, 讓狀態欄完全透明.
onCreate的setContentView調用之後, 將activity做參數傳給下面這個方法, 就可以讓你的app在api level 21上擁有完全透明的狀態欄, 同時在api 19上使用上面的實現

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void setSystemBarTransparent(Activity paramActivity)
    {
        if (shouldUseTransparentSystemBar()) {
            Window window = paramActivity.getWindow();
            WindowManager.LayoutParams layoutParams = window.getAttributes();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //api 21 解決方案
                View systemdecor = window.getDecorView();
            systemdecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
                layoutParams.flags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
                window.setStatusBarColor(0x00000000);
            } else {
                //api 19 解決方案
                layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
            }
            window.setAttributes(layoutParams);
        }
    }

api 21的解決方案理論上是可以用xml完成的, 但是我實際測試發現並不能, 只有用代碼才有效.
 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved