Android 系統欄

一、ActionBar(標題欄)

android.app.ActionBar是 Android 3.0(API 11) 引入的界面頂部導航控件。如果需要在 3.0 以下使用 ActionBar,需要先引入 Support Library ,然后使用 Support Library 里的android.support.v7.app.ActionBar。需要注意的是,使用不同包下的 ActionBar 時,操作的 API 也不相同。

使用系統提供的 ActionBar,可以自適應不同大小的手機屏幕、指明當前用戶正在操作的界面、提供界面導航、搜索、下拉菜單等功能,是 Activity 設計中非常重要的元素。

由于 ActionBar 是受 Framework 層的控制,而不是 Activity 內容的一部分,某種程度上限制了 Android app 開發的靈活性,因此在 Android 5.0(API 21) 時引入了直接在 Activity 內容中設計的 ToolBar。

接下來以 android.support.v7.app.ActionBar 進行介紹,使用
android.support.v7.app.ActionBar 必須為 AppCompatActivity 的子類,且主題必須為 AppCompat 家族的主題。

1、ActionBar 的顯示與隱藏

// == 顯示 ==
// 使用帶 ActionBar 的主題
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"

// == 隱藏 ==
// 方式1:指定無 ActionBar 主題
android:theme="@style/Theme.AppCompat.Light.NoActionBar"

// 方式 2:Java 代碼
getSupportActionBar().hide();

// 方式 3:在 setContentView 方法前調用 supportRequestWindowFeature 方法
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);

注意:
requestWindowFeature(Window.FEATURE_NO_TITLE) 是針對 android.app.ActionBar 的隱藏,而 supportRequestWindowFeature(Window.FEATURE_NO_TITLE) 是針對 android.support.v7.app.ActionBar 的隱藏。

2、 ActionBar 返回鍵

// 1、顯示系統默認的返回鍵
ActionBar actionBar = getSupportActionBar();
if (actionBar != null)
   actionBar.setDisplayHomeAsUpEnabled(true);

// 2、修改返回鍵圖標
// 通過配置主題修改
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>

    <!-- 返回鍵圖標 -->
    <!-- 需要調用 ActionBar 的 setDisplayHomeAsUpEnabled 方法才能生效 -->
    <item name="homeAsUpIndicator">@drawable/ic_navigate_before_black</item>
</style>

// 通過 Java 代碼修改
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
    actionBar.setDisplayHomeAsUpEnabled(true); // 需要調用這個方法才能生效
    actionBar.setHomeAsUpIndicator(R.drawable.ic_navigate_before_black_24px);
}

// 3、重寫 Activity 的 onOptionsItemSelected 方法監聽返回鍵點擊
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {   
        case android.R.id.home:
            finish();
            break;           
    }
    return true;
}

3、ActionBar 動作鍵

// 第一步:新建 res/menu 目錄用于存放動作菜單文件
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu"
        android:title="menu"
        android:icon="@drawable/ic_menu_black"
        app:showAsAction="always"
        />
</menu>

// 第二步:重寫 Activity 的 onCreateOptionsMenu 方法加載菜單
@Override
public boolean onCreateOptionsMenu(Menu menu) {
     getMenuInflater().inflate(R.menu.toolbar,menu);
     return true;
}

// 第三步:重寫 Activity 的 onOptionsItemSelected 方法對菜單點擊監聽@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu:
            Toast.makeText(ScreenAty.this, "menu", Toast.LENGTH_LONG).show();
            break;
    }
    return true;
}

4、修改 ActionBar 背景

// 1、通過主題修改
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- 標題欄背景 -->
    <item name="colorPrimary">#ff0000</item>

    <!-- 狀態欄背景-->
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

    <!-- 操作控件顏色,如 EditText 的光標、RadioButton 等 -->
    <item name="colorAccent">@color/colorAccent</item>
</style>

// 2、通過 Java 代碼
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.GREEN));

5、自定義 ActionBar 布局

ActionBar actionBar = getSupportActionBar();
View customAcbView = getLayoutInflater().inflate(R.layout.view_acb,null);
ActionBar.LayoutParams alp = new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT,ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER);
actionBar.setCustomView(customAcbView,alp);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setElevation(0);

二、ToolBar

android.widget.ToolBar 是在 Android 5.0(API 21) 推出的導航控件,可以說它的出現就是替代原來的 ActionBar。和 ActionBar 一樣,Google 也提供了向下兼容的 Support Library。如需在 Android 5.0(API 21) 以下使用 ToolBar,需要先引入 Support Library,然后使用 Support Library 庫中提供的 android.support.v7.widget.ToolBar。同樣地,使用不同的 ToolBar 操作 API 也不相同。

ToolBar 可直接在 Activity 內容中編輯,因此具有比 ActionBar 更好的靈活性; 同時,ToolBar 支持 material design 風格。

接下來以 android.support.v7.widget.ToolBar 進行介紹。

1、添加 ToolBar

ToolBar 的使用可以像一般控件那樣添加到窗口控件中的任何位置??稍?xml 布局文件中直接添加,也可以在代碼中添加,由于導航欄一般都是位于一個界面的頂部,所以我們通常在 xml 布局文件中添加。

** 添加方式 1:xml 布局文件中添加 ToolBar**

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="?android:attr/actionBarSize"
        android:background="#ff0000" />

</LinearLayout>

** 添加方式 2:Java 代碼動態添加 ToolBar **
xml 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    
</LinearLayout>

Java 代碼

// ToolBar 父容器
ll = (LinearLayout) findViewById(R.id.ll);

// ToolBar 高度
int toolBarHeight = 80;
TypedValue typedValue = new TypedValue();
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true)){
    toolBarHeight = TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics());
}

// 設置 ToolBar
Toolbar toolbar = new Toolbar(this);
toolbar.setBackgroundColor(Color.RED);

toolbar.setLayoutParams(new Toolbar.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, toolBarHeight));
// 可添加到任意位置
ll.addView(toolbar,0);

注意:
由于 ToolBar 與 ActionBar 都是起導航的作用,所以我們在使用了 ToolBar 之后可將 ActionBar 隱藏。但是兩者完全可以共存(親測)。網上有人說使用 ToolBar 必須將 ActionBar 隱藏掉,其實沒那么絕對。

但是如果調用了setSupportActionBar(android.support.v7.widget.ToolBar toolbar)setActionBar(android.widget.ToolBar toolbar) 方法將 ToolBar 設置到系統 ActionBar 時,就必須隱藏掉系統 ActionBar,而且必須是使用設置無 ActionBar 主題的方式來隱藏(參見上面 ActionBar 的隱藏方式),否則會報以下錯誤:

java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.

2、設置 ToolBar 屬性

方式 1:xml 布局文件中直接設置

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:toolbar="http://schemas.android.com/apk/res-auto"
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolBar"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/actionBarSize"
        android:background="#ff0000"
        toolbar:title="ToolBar"
        toolbar:navigationIcon="@drawable/ic_navigate_before_black"
        toolbar:subtitle="456"
        toolbar:contentInsetLeft="0dp"
        toolbar:contentInsetStart="0dp"
        toolbar:contentInsetEnd="0dp"
        toolbar:contentInsetRight="0dp"
         >
    </android.support.v7.widget.Toolbar>

</LinearLayout>

注意:
在 xml 布局文件中設置 ToolBar 屬性時命名空間需要改為非 「android」 的其它任意字符,如上面代碼中改為了 toolbar。否則屬性將不會生效。

方式 2:Java 代碼中設置

Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar);
toolbar.setTitle("ToolBar");
toolbar.setBackgroundColor(Color.RED);
toolbar.setNavigationIcon(R.drawable.ic_navigate_before_black);
// ...

3、為 ToolBar 添加動作項

res/menu/toolbar.xml 菜單文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu"
        android:title="menu"
        android:icon="@drawable/ic_menu_black"
        app:showAsAction="always"
        />
</menu>

添加方式 1:

當調用了setSupportActionBar(android.support.v7.widget.ToolBar toolbar)setActionBar(android.widget.ToolBar toolbar)方法將 ToolBar 設置到系統 ActionBar 時:

// 重寫 Activity 的 onCreateOptionsMenu(Menu menu) 方法渲染菜單
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.toolbar,menu);
    return true;
}

// 監聽方式 1:重寫 Activity 的 onOptionsItemSelected(MenuItem item) 方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()){
    case R.id.menu:
        Toast.makeText(ScreenAty.this,"menu",Toast.LENGTH_LONG).show();
  }
  return true;
}

// 監聽方式 2
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()){
            case R.id.menu:
                Toast.makeText(ScreenAty.this,"menu",Toast.LENGTH_LONG).show();
        }
        return true;
    }
});

添加方式 2

未調用setSupportActionBar(android.support.v7.widget.ToolBar toolbar)setActionBar(android.widget.ToolBar toolbar)方法將 ToolBar 應用到系統 ActionBar 中。

// 直接調用 inflateMenu 方法添加菜單
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar);
toolbar.inflateMenu(R.menu.toolbar);

// 只能使用這種方式監聽
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItekwmClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()){
            case R.id.menu:
                Toast.makeText(ScreenAty.this,"menu",Toast.LENGTH_LONG).show();
        }
        return true;
    }
});

4、自定義 ToolBar 布局

由于 ToolBar 繼承至 ViewGroup,所以它可以包含任意子 View。如果我們的子 View 也是一個容器控件,那么我們就可以在這個容器控件中自由地擺放其它 View,從而達到自定義 ToolBar 布局。但這樣做的前提是不要再設置 ToolBar 的標題、子標題、menu 等占位的屬性。具體代碼如下所示:

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolBar"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/actionBarSize"
        android:background="#ff0000"
        toolbar:contentInsetLeft="0dp"
        toolbar:contentInsetStart="0dp"
        toolbar:contentInsetEnd="0dp"
        toolbar:contentInsetRight="0dp"
         >
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@mipmap/ic_launcher"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="標題"
                android:layout_centerInParent="true"
                />
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@mipmap/ic_launcher"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true"
                android:layout_centerVertical="true"
                />
        </RelativeLayout>
    </android.support.v7.widget.Toolbar>

三、Status Bar(狀態欄)、Nav Bar(導航欄)

Status Bar 一直都存在于 Android 設備中,Nav Bar 是 Android 4.0(API 14) 才引入的,雖然它們的引入都比較早,但在早期的系統中,它們各自的很多屬性都不能被操作,慢慢地相關屬性的操作才隨系統的升級添加進來。

對 Status Bar、Nav Bar 的操作方式大致相同,因此放在一起介紹。

1、隱藏

方式 1:通過配置主題

//  同時隱藏 Status Bar、Nav Bar,需是 Activity 的直接子類且 minSdkVersion >= 11
android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" 

方式 2:通過 Java 代碼

// 隱藏 Status Bar
if (Build.VERSION.SDK_INT < 16) {// Android 4.1 以下設備
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
    WindowManager.LayoutParams.FLAG_FULLSCREEN);
}else{// Android 4.1 及以上設備
    activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                                              | View.SYSTEM_UI_FLAG_FULLSCREEN
                                                              | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

// 隱藏導航欄,Android 4.0 以上
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

// Status Bar、ActionBar、Nav Bar 同時隱藏
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                                          | View.SYSTEM_UI_FLAG_FULLSCREEN
                                                          | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                                          | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                                          | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION );

2、漂?。ˋPI >= 16)

使 Status Bar、Nav Bar 漂浮,即 Activity 布局內容可以顯示在 Status Bar、Nav Bar下面。

// Status Bar 漂浮
if (Build.VERSION.SDK_INT >= 16)
    activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

// Nav Bar 漂浮
if (Build.VERSION.SDK_INT >= 16)
    activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

3、修改顏色(API >= 21)

方式1:通過配置主題

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

    <!-- ActionBar -->
    <item name="colorPrimary">@color/colorPrimary</item>

    <!-- Status Bar-->
    <item name="colorPrimaryDark">@android:color/transparent</item>

    <!-- EditText、CheckBox 等交互控件 -->
    <item name="colorAccent">@color/colorAccent</item>

    <!-- Nav Bar,需要配置在 values-v21 目錄中-->
    <item name="android:navigationBarColor">#0000ff</item>

</style>

方式 2:通過 Java 代碼

// Status Bar
if (Build.VERSION.SDK_INT >= 21) {
    Window window = activity.getWindow();
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.setStatusBarColor(Color.BLUE);
}

// Nav Bar
if(Build.VERSION.SDK_INT >= 21)
     activity.getWindow().setNavigationBarColor(Color.YELLOW);

4、透明(API >= 19)

方式 1:通過配置主題

在 res 目錄下新建 values-v19 、values-v21目錄,并在 values-v19 、values-v21 目錄下新建一個和 values 目錄相同的用于主題配置的文件(一般是 styles.xml)。 注意:values-v19、values-v21 目錄下有的主題,在 values 目錄下也應該有一套,不然低版本運行時會報找不到主題的錯誤。

res/values-v19/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- 方式1 -->
    <style name="transparentTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <!-- Status Bar -->
        <item name="android:windowTranslucentStatus">true</item>

        <!-- Nav Bar-->
        <item name="android:windowTranslucentNavigation">true</item>

    </style>

    <!-- 方式2使 Status Bar 透明, 應用的界面必須為 Activity 的子類,不能為 AppCompatActivity 的子類-->
    <style name="transparentStatusBarHoloTheme" parent="@android:style/Theme.Holo.Light.NoActionBar.TranslucentDecor">

        <!-- Status Bar-->
        <item name="android:windowTranslucentNavigation">false</item>

    </style>

</resources>

res/values-v21/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="transparentTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <!-- Status Bar-->
        <item name="colorPrimaryDark">@android:color/transparent</item>

        <!-- Status Bar-->
        <item name="android:statusBarColor">@android:color/transparent</item>

        <!-- Nav Bar -->
        <item name="android:navigationBarColor">@android:color/transparent</item>

    </style>

</resources>

res/values/styles.xml

<resources>    

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="transparentTheme" parent="AppTheme">
    </style>

    <style name="transparentStatusBarHoloTheme" parent="AppTheme">
    </style>

</resources>

方式 2:通過 Java 代碼

// Status Bar
if(Build.VERSION.SDK_INT >= 19){
    activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}

// Status Bar
if(Build.VERSION.SDK_INT >= 21){
    Window window = activity.getWindow();
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.setStatusBarColor(Color.TRANSPARENT);
}

// Nav Bar
if (Build.VERSION.SDK_INT >= 19) 
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

注意:
當 Status Bar 、Nav Bar 透明后,有可能會占據原來的位置,此時默認會顯示 Activity 頂級View(DecorView)的背景(白色),這時不要誤以為透明未成功。下面的代碼可設置 DecorView 的背景:
activity.getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(this,android.R.color.darker_gray));

五、沉浸模式(API >= 19)

所謂沉浸模式,就是將系統欄(狀態欄、ActionBar、ToolBar、導航欄)全部隱藏掉,使界面只剩下 Activty 的內容。是 Android 4.4 引入的一種模式。

1、進入沉浸模式

if (Build.VERSION.SDK_INT >= 19) {
     activity.getWindow().getDecorView().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);
}

2、退出沉浸模式

if (Build.VERSION.SDK_INT >= 19) {
    activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                                              | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                                                              | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

3、沉浸模式的分類

View.SYSTEM_UI_FLAG_IMMERSIVE

進入此沉浸模式后,當用戶在狀態欄或導航欄區域向屏幕中心滑動時,系統欄會重新顯示出來,顯示后就不會再自動隱藏。

View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY

進入此沉浸模式后,當用戶在狀態欄或導航欄區域向屏幕中心滑動時,Status Bar、Nav Bar 又會重新顯示,過一會兒又會自動隱藏。如果退出沉浸模式是通過調用上面退出沉浸模式方法,則不會再自動進入沉浸模式。

六、總結

  1. 文章中同一操作有的有多種方式,可根據具體情況選擇最佳方式。
  2. 本文介紹的大部分系統欄的操作和具體系統相關,難免會有錯誤的結論,望大家批評指正,我會盡快加以驗證。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容