Material Design 實戰 之第一彈——Toolbar詳解

weixin_34007291發表於2018-09-16

本模組共有六篇文章,參考郭神的《第一行程式碼》,對Material Design的學習做一個詳細的筆記,大家可以一起交流一下:


      寫在文首,什麼是Material Design?這裡參考一下郭神的說法:

9125154-f5ad1977043eb210.png



文章提要與總結


1. 關於android:theme的詳細理解(附圖);
    (運用:使用Toolbar代替ActionBar時,須將Theme.AppCompat.Light.DarkActionBar改成Theme.AppCompat.Light.NoActionBar)
2. 在activity_main.xml中使用Toolbar代替ActionBar;
        關於名稱空間:android  app;
        關於Toolbar控制元件的屬性;
                尤其android:theme以及app:popupTheme的用法理解;

3. 關於activity.android:label;

4. 通過Menu resource file選單檔案式(同時為xml格式)來為Toolbar新增action按鈕;
        檔案中:
        <item>標籤來定義action按鈕,
        android:id用於指定按鈕的id,
        android:icon用於指定按鈕的圖示,
        android:title用於指定按鈕的文字;
        使用app:showAsAction來指定按鈕的顯示位置,再次使用了app名稱空間,同樣是為了能夠相容低版本的系統;
         showAsAction的幾種選值:always   ifRoom   never
        注意,
                Toolbar中的action按鈕只會顯示圖示,
                選單中的action按鈕只會顯示文字;

5. onCreateOptionsMenu()載入描述Toolbar的action按鈕的Menu resource file;
    onOptionsItemSelected()方法中處理各個按鈕的點選事件;



正文


關於Toolbar

Toolbar相關於ActionBar;
不過ActionBar由於其設計原因,被限定只能位於活動的頂部,從而不能實現一些Material Design的效果,因此官方現在已經不建議使用ActionBar了。

9125154-c5ab34ad76beb5c9.png

首先要知道,任何一個新建的專案預設都是會顯示ActionBar的。
ActionBar是根據專案中指定的主題來顯示,
開啟AndroidManifest.xml檔案:

9125154-35292ca9d7872331.png

可以看到這裡用android:theme指定了一個AppTheme的主題。
開啟res/values/styles.xml檔案可以檢視其定義出處:

9125154-c68d8d403a820b13.png

這裡定義了一個叫AppTheme的主題並指定它的parent主題是Theme.AppCompat.Light.DarkActionBar。
DarkActionBar是一個深色的ActionBar主題,所有的新建專案中自帶的ActionBar就是因為指定了這個主題才出現的。

要使用TooIbar來替代ActionBar時需要指定一個不帶ActionBar的主題,
對應的通常有Theme.AppCompat.NoActionBar和Theme.AppCompat.Light.NoActionBar這兩種主題可選;
其中:

  • Theme.AppCompat.NoActionBar表示深色主題,它會將介面的主體顏色設成深色,陪襯顏色設成淡色;
  • Theme.AppCompat.Light.NoActionBar表示淡色主題,它會將介面的主體顏色設成淡色,陪襯顏色設成深色。

具體可以根據情況去設定,這裡主要選用淡色主題,如下所示:

9125154-7a3c6597de03f263.png

觀察程式碼中AppTheme中的屬性重寫:
可見這裡重寫了colorPrimary、colorPrimaryDark和colorAccent這3個屬性的顏色。
屬性指定顏色名稱對應的位置,如圖:

9125154-434de1c768264aab.png

可見除了上述3個屬性之外,我們還可以通過textColorPrimary、windowBackground和navigationBarCotor等屬性來控制更多位置的顏色。
不過colorAccent這個屬性比較特殊,它不只是用來指定這樣一個按鈕的顏色,而是更多表達了一個強調的意思,比如一些控制元件的選中狀態也會使用colorAccent的顏色。

至此已將ActionBar隱藏,接下來使用Toolbar來替代ActionBar。
修改activity_main.xml:

9125154-d224fc5f034b41e1.png
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    </FrameLayout>

下面解析一下這段程式碼:

  1. 首先看一下第2行,這裡使用xmlns:app指定了一個新的名稱空間。
    正是由於每個佈局檔案都會使用xmlns:android來指定一個名稱空間,因此我們才能一直使用android:id、android:layoutwidth等寫法,
    這裡指定了xmlns:app,現在便可以使用app:attribute這樣的寫法了。

但是為什麼這裡要指定一個xmlns:app的名稱空間呢?
這是由於MaterialDesign是在Android5.0系統中才出現的,而很多的Material屬性在5.0之前的系統中並不存在,那麼為了能夠相容之前的老系統,我們就不能使用android:attribute這樣的寫法了,而是應該使用app:attribute

  1. 接下來定義了一個Toolbar控制元件,這個控制元件是由appcompat-v7庫提供的。
    這裡我們給Toolbar指定了一個id,將它的
    寬度設定為matchparent,
    高度設定為actionBar的高度,
    背景色設定為colorPrimary。

  2. 接下來,關於主題:
    由於我們剛才在styles.xml中將程式的主題指定成了淡色主題,因此Toolbar現在也是淡色主題(“藍底(黑字)”),而TooIbar上面的各種元素就會自動使用深色主題(“(黑底)X字”),這是為了和主體顏色區別開(具體可以看文章開頭對於深色淺色主題的解釋)。

    9125154-b39cc42d0b0f773f.png
    在styles.xml中將程式的主題指定成了淡色主題,Toolbar現在也是淡色主題,TooIbar上面的各種元素就會自動使用深色主題

  1. 但是這個效果看起來就會很差之前使用ActionBar時文字都是白色的,現在變成黑色會很難看。那麼為了能讓Toolbar單獨(全域性是用由APPTheme制定的淺色主題的,故相對而言這裡用“單獨”)使用深色主題,這裡我們使用android:theme屬性,將Toolbar的主題指定成了ThemeOverlay.AppCompat.Dark.ActionBar。

  2. 但是這樣指定完了之後又會出現新的問題,如果Toolbar中有選單按鈕,那麼彈出的選單項也會變成深色主題,這樣就再次變得十分難看,於是這裡使用了app:popupTheme屬性單獨將彈出的選單項指定成了淡色主題。

  3. 之所以使用app:popupTheme,是因為popupTheme這個屬性是在Android5.0系統中新增的,我們使用app:popupTheme的話就可以相容Android5.0以下的系統了。

小結:

  1. 為了能夠相容之前的老系統,使用app:attribute,而不是android:attribute;
  2. 在styles.xml中將程式的主題指定成了淡色主題;
  3. 使用android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"讓Toolbar單獨使用深色主題;
  4. 使用app:popupTheme="@style/ThemeOverlay.AppCompat.Light"單獨將彈出的選單項指定成了淡色主題;
  5. 之所以使用app:popupTheme,是因為popupTheme這個屬性是在Android5.0系統中新增的,我們使用app:popupTheme的話就可以相容Android5.0以下的系統了。



接下來修改MainActivity:

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

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

這裡,
首先用findViewByid()得到Toolbar的例項,
然後呼叫setSupportActionBar()方法同時傳入Toolbar的例項,
至此便實現了既使用Toolbar,又讓它的外觀與功能都同ActionBar一致。

現在執行一下程式,效果如圖:

9125154-9727be7d7669d068.png


這個標題欄雖然看上去和之前的沒什麼兩樣,但其實它已經是Toolbar而不是ActionBar了,它現在也具備了實現MaterialDesign效果的能力。



接著實戰一些Toolbar比較常用的功能,比如修改標題欄上顯示的文字內容,
這段文字是在AndroidManifest.xml中指定的,如下所示:

9125154-c94625414d4c5c7c.png

這裡給activity增加了一個android:label屬性,用於指定在Toolbar中顯示的文字內容,
如果沒有指定的話,會預設使用application中指定的label內容,也就是我們的應用名稱。

接下來再新增一些action按鈕來豐富Toolbar:
先準備了幾張圖片來作為按鈕的圖示,將它們放在了drawable-xxhdpi目錄下;
右擊res目錄→New→Directory,建立一個menu資料夾;
右擊menu資料夾→New→Menuresourcefile,建立一個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/backup"
        android:icon="@drawable/ic_backup"
        android:title="Backup"
        app:showAsAction="always"/>
    <item
        android:id="@+id/delete"
        android:icon="@drawable/ic_delete"
        android:title="Delete"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/settings"
        android:icon="@drawable/ic_settings"
        android:title="Settings"
        app:showAsAction="never"/>
</menu>
  • 可以看到,我們通過
    <item>標籤來定義action按鈕,
    android:id用於指定按鈕的id,
    android:icon用於指定按鈕的圖示,
    android:title用於指定按鈕的文字。

  • 接著使用app:showAsAction來指定按鈕的顯示位置,
    之所以這裡再次使用了app名稱空間,同樣是為了能夠相容低版本的系統。

  • showAsAction主要有以下幾種值可選:
    always表示永遠顯示在Toolbar中,如果螢幕空間不夠則不顯示;
    ifRoom表示螢幕空間足夠的情況下顯示在Toolbar中,不夠的話就顯示在選單當中;
    never則表示永遠顯示在選單當中。

  • 注意,
    Toolbar中的action按鈕只會顯示圖示,
    選單中的action按鈕只會顯示文字。

接下來就是建立選單的套路了,修改MainActivity中的程式碼,如下所示:

9125154-6e557f53bb20841d.png
9125154-f9c5eb01fd9a1fa6.png
9125154-d15a25e47b735be2.png

package com.example.materialtest;

import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.toolbar,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.backup:
                Toast.makeText(this,"You clicked Backup" , Toast.LENGTH_SHORT).show();
                break;
            case R.id.delete:
                Toast.makeText(this,"You clicked Delete" , Toast.LENGTH_SHORT).show();
                break;
            case R.id.settings:
                Toast.makeText(this,"You clicked Settings" , Toast.LENGTH_SHORT).show();
                break;
            default:
        }
        return true;
    }

}

上述程式碼:
在onCreate0ptionsMenu()中載入toolbar.xml這個選單檔案,
在onOptionsItemSelected()中處理各個按鈕的點選事件。
重新執行一下程式,效果如圖:

9125154-343a76298b7e33de.png

可見Toolbar上面現在顯示了兩個action按鈕,這是因為
Backup按鈕指定的顯示位置是alway,
Delete按鈕指定的顯示位置是ifRoom,而現在螢幕空間充足。因此兩個按鈕都會顯示在Toolbar中。
Settings按鈕則由於指定的顯示位置是never,所以顯示在選單中(點選最右邊的三個小點即知)。

同時注意這些action按鈕都是可以響應點選事件的!

相關文章