跳到主要內容

如何把 Status Bar 變透明

        Android 從 4.4 (KitKat, api level 19) 後才支援這個功能, 到了 5.0 (Lollipop, api level 21) 自訂性更高, 可以讓我們設定各種顏色, 當然也包含透明色。以下分別介紹如何使用這兩種版本的方法。

       方法1: 利用 attribute "android:windowTranslucentStatus", 在 style.xml 加上這個 attribute 就好。要注意的是 Android 版本要在 4.4 以上才可以用這個 attribute:

<resources>

    <!--
        Base application theme for API 19+. This theme completely replaces
        AppTheme from res/values/styles.xml on API 19+ devices.
    -->
    <style name="AppTheme" parent="@style/AppBaseTheme">
        <!-- API 19 theme customizations can go here. -->
        <item name="android:windowTranslucentStatus">true</item>
    </style>

</resources>
        下面的圖分別為 4.4 跟 5.0 的手機使用這個 attribute 的結果:


        因為設定了這個 attribute, 畫面會從 status bar 下方開始畫。要解決這個有兩種方法, 第一個是在 layout 畫面設定 attribute "android:fitsSystemWindows"

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary"
    android:fitsSystemWindows="true"
    tools:context="${relativePackage}.${activityClass}" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        android:textColor="@android:color/black" />

</RelativeLayout>



        有時候你的 layout 可能很複雜, 不一定能單純用這個 attribute 就解決, 這時候就要用第二種方法: 用程式去算 status bar 的 height, 把想往下移的 layout 都加上 status bar 的高。網路上有提供如何取得 status bar height 的範例程式碼:

public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    } 
    return result;
}

        當然這也可以用程式碼的方式去控制, 在 Activity 使用以下的 api:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    Window w = this.getWindow();
    w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
        WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}

        用程式控制一樣會有 layout 從 status bar 開始的問題, 要記得用上面的方法避掉。

        方法2: 使用 Android 5.0 新加的 attribute android:colorPrimaryDark (或是 support library v7 appcompat 的 colorPrimaryDark)。根據官方說法, colorPrimaryDark 就是會設定 status bar 的顏色, 要直接改 status bar 的顏色也可以設定 attribute android:statusBarColor。但是目前查到修改 xml 的方式都不能讓 status bar 變透明, 只能透過程式碼去設定:
public abstract void setStatusBarColor (int color), 而官方也有說, 要讓 status bar 變透明, 不能只單純用這個 api, 還需要另外設定一些 flag 才行。以下為範例程式碼:

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Window window = this.getWindow();

    // Followed by google doc.
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.setStatusBarColor(ContextCompat.getColor(this, android.R.color.transparent));

    // For not opaque(transparent) color.
    window.getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}


        上圖為用方法2的結果, 可以看出還是會有跟方法1一樣的問題, 因此不想畫面跟 status bar 重疊的話, 一樣可以用上面說的方法解決。

參考資料:

1. stack overflow - Height of status bar in Android
5. Android developers - Using the Material Theme
6. Android documentation - Window.setStatusBarColor(int)
7. 莫希爾(Mosil)手札 - 在 KITKAT 以上版本的 TRANSLUCENT 介紹

留言

  1. If you are preparing for React Native developer interviews, you must grasp the fundamentals.

    As an experienced React Native developer, you must have an in-depth understanding of the architecture of React, re-architecture, fragments, hooks, optimizations strategies, memory leak detection, and mitigation and about its libraries. For React Native app development projects, try to have open-source projects under your portfolio for a plus.

    If you want to explore and work on React Native app development projects, Eiliana is the right place for you. We help freelance React Native developers connect with quality international clients.

    https://eiliana.com/blogitem/react-native-app-development-the-future-of-mobile-app-development

    回覆刪除

張貼留言

這個網誌中的熱門文章

探討 LayoutInflater 的 inflate method

        在 Android 程式裡要動態新增 View,最直接的方法就是使用 LayoutInflater 提供的 inflate method。比較常用的有以下兩個 method: inflate(int resource, ViewGroup root) inflate(int resource, ViewGroup root, boolean attachToRoot)         第一個參數 resource,就是 layout xml file,如 R.layout.your_file。第二個參數 root,指的是這個 inflate 的 view,要成為哪個 view 的 child view。最後一個參數 attachToRoot 是 inflate 的 view 是否要 attach 到 root view,這會影響到回傳的是哪個 view。假如 attachToRoot 為 true,則最後回傳的 view 為 root view (就是第二個參數的 view);反之就是回傳 inflate 的 view。         第二個參數 ViewGroup root 需要特別說明一下,因為這會影響到如何 inflate 新的 view 出來。android 的 view 是有階層 (hierarchy) 的,因此 parent view 的屬性 (attribute) 會影響到 child view 。假如你是如以下兩種方式使用 inflate method的話: View view1 = LayoutInflater.from(mContext).inflate(R.layout.your_file, null) View view2 = LayoutInflater.from(mContext).inflate(R.layout.your_file, null, false)         因為沒有 root view,系統沒辦法把 inflate view 的屬性正確設定,因此系統會把 inflate view 的屬性設為 null,這會導致 inflate ...

Deprecated API

        當透過 IDE 使用 API,或是查 Document 時,常會看到一段途述:  This method was deprecated… 這是什麼意思呢?這是告訴我們還是可以使用此 method,但未來可能會沒有用、甚至是 在新版本的 SDK 會把這個 method 移掉 。         以 API level 11 出現的 Fragment  為例子,在使用時常會 override 一個 callback 叫 onAttach (Activity activity),但到了 API level 23 (Lollipop) 時,可以發現 onAttach (Activity activity) 被標記為 deprecated 了,取而代之的是 onAttach (Context context)。         像我個人寫程式不太喜歡出現 warning,而使用到 deprecated api 會被 Android Studio 檢查出來,我在用 Fragment 時就直接都換成 onAttach (Context context),結果程式在 api level 較低的手機就出現不符合預期的行為。Debug 了一陣子才發現 onAttach (Context context) 是新的 API,舊版本 SDK 當然沒有這個  API,自然就不會執行到該 API。         因此,雖然有些 API 被標記為 deprecated,但當你的程式還需要支援較舊版本時,還是得使用這些 API,假如要用的 API 在 Support Library  也有對應版本的話,我會建議用 Support Library 版本,因為放在裡面的 API 本來就是為了向下相容而設計的。以 Support Libaray 裡的Fragment 來說,onAttach (Activity activity) 一樣被標記為 deprecated,也一樣有 onAttach (Context context) ...