MDC-101 Android:Material Design 元件 (MDC) 基本概念 (Java)

1. 簡介

logo_components_color_2x_web_96dp.png

Material Design 元件 (MDC) 可協助開發人員實作質感設計。MDC 是由 Google 工程師和使用者體驗設計師團隊打造,提供數十種精美且功能豐富的 UI 元件,適用於 Android、iOS、網頁和 Flutter.material.io/develop

什麼是 Android 適用的 Material Design 和 Material 元件?

Material Design 是打造搶眼數位產品的系統。產品團隊只要遵循一致的原則和元件組合,將樣式、品牌宣傳、互動和動畫一貫化,就能實現最大的設計潛力。

對於 Android 應用程式,Android Material 元件 (MDC Android) 將設計和工程與元件庫相結合,以便建立應用程式的一致性。隨著 Material Design 系統不斷演進,這些元件也會不斷更新,確保像素完美實作一致,且符合 Google 的前端開發標準。MDC 也提供網頁、iOS 和 Flutter。

在本程式碼研究室中,您將使用數個 MDC Android 元件建構登入頁面。

建構項目

本程式碼研究室是程式碼研究室之一,可引導您建構名為 Shrine 的應用程式,這是一款電子商務 Android 應用程式,專門販售服飾和居家用品。示範如何使用 MDC-Android 自訂元件,反映任何品牌或風格。

在本程式碼研究室中,您會建構 Shrine 的登入頁面,其中包含:

  • 兩個文字欄位,一個用於輸入使用者名稱,另一個則用於密碼
  • 兩個按鈕,一個用於「取消」以及「下一首」
  • 應用程式名稱 (Shrine)
  • 神殿的標誌圖片

4cb0c218948144b4.png

本程式碼研究室中的 MDC Android 元件

  • 文字欄位
  • 按鈕

軟硬體需求

  • 對 Android 開發作業有基本瞭解
  • Android Studio (如果尚未安裝,請在這裡下載)
  • Android 模擬器或裝置 (可透過 Android Studio 取得)
  • 程式碼範例 (請參閱下一步)

你對建立 Android 應用程式的經驗程度為何?

新手 中級 還算容易

2. 設定開發環境

啟動 Android Studio

開啟「Android Studio」時,畫面中會顯示標題為「Welcome to Android Studio」的視窗。不過,如果這是您第一次啟動 Android Studio,請按照 Android Studio 設定精靈步驟,輸入預設值。這個步驟可能需要幾分鐘的時間來下載和安裝必要檔案,因此您可以在後續部分中,繼續在背景執行。

下載程式碼研究室入門應用程式

範例應用程式位於 material-components-android-codelabs-101-starter/java 目錄中。

...或是從 GitHub 複製檔案

如要從 GitHub 複製本程式碼研究室,請執行下列指令:

git clone https://github.com/material-components/material-components-android-codelabs
cd material-components-android-codelabs/
git checkout 101-starter

在 Android Studio 中載入範例程式碼

  1. 設定精靈完成後,系統顯示「Welcome to Android Studio」視窗,請按一下「Open an existing Android Studio project」。前往您安裝程式碼範例的目錄,然後選取 java ->神社 (或在電腦上搜尋小時) 以開啟 Shrine 專案。
  2. 等待 Android Studio 建構並同步處理專案,如 Android Studio 視窗底部的活動指標所示。
  3. 此時,Android Studio 可能會引發部分建構錯誤,因為缺少 Android SDK 或建構工具 (如下所示)。請按照 Android Studio 中的指示安裝/更新這些套件,並同步處理專案。

F5H6srsw_5xOPGFpKrm1RwgewatxA_HUbDI1PWoQUAoJcT6DpfBOkAYwq3S-2vUHvweUaFgAmG7BtUKkGouUbhTwXQh53qec8tO5eVecdlo7QIoLc8rNxFEBb8l7RlS-KzBbZOzVhA

新增專案依附元件

專案需要使用 MDC Android 支援資料庫的依附元件。您下載的程式碼範例中應該已經包含這個依附元件,但建議您執行下列步驟確認。

  1. 前往 app 模組的 build.gradle 檔案,確認 dependencies 區塊包含 MDC Android 的依附元件:
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (選用) 如有需要,請編輯 build.gradle 檔案,新增下列依附元件並同步處理專案。
dependencies {
    api 'com.google.android.material:material:1.1.0-alpha06'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:core:1.1.0'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test:runner:1.2.0-alpha05'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha05'
}

執行範例應用程式

  1. 確認「Run / Play」按鈕左側的建構設定為 app
  2. 按下綠色的「Run」/「Play」按鈕,即可建構並執行應用程式。
  3. 在「Select Deployment Target」視窗中,如果可用裝置已列出「Android 裝置」,請跳至步驟 8。否則,請按一下「Create New Virtual Device」
  4. 在「選取硬體」畫面中選取手機裝置 (例如「Pixel 2」),然後點選「下一步」
  5. 在「System Image」畫面中選取最新的 Android 版本 (最好是最高 API 級別)。如果尚未安裝,請按一下畫面中顯示的「Download」(下載) 連結並完成下載。
  6. 點選「下一步」。
  7. 在「Android Virtual Device (AVD)」(Android 虛擬裝置 (AVD)) 畫面上維持原設定,然後按一下「Finish」(完成)
  8. 從部署目標對話方塊中選取「Android 裝置」
  9. 按一下 [確定]。
  10. Android Studio 會建構及部署應用程式,並自動在目標裝置上開啟應用程式。

大功告成!Shrine 登入頁面的範例程式碼應會在模擬器中執行。您應該會看到「Shrine」這個名稱旁邊還有 Shrine 標誌

e7ed014e84755811.png

我們來看看程式碼。我們在程式碼範例中提供簡易的 Fragment 導覽架構,用來顯示片段並在片段之間導覽。

shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine 目錄中開啟 MainActivity.java。其中應包含以下內容:

MainActivity.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity extends AppCompatActivity implements NavigationHost {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.shr_main_activity);

       if (savedInstanceState == null) {
           getSupportFragmentManager()
                   .beginTransaction()
                   .add(R.id.container, new LoginFragment())
                   .commit();
       }
   }

   /**
    * Navigate to the given fragment.
    *
    * @param fragment       Fragment to navigate to.
    * @param addToBackstack Whether or not the current fragment should be added to the backstack.
    */
   @Override
   public void navigateTo(Fragment fragment, boolean addToBackstack) {
       FragmentTransaction transaction =
               getSupportFragmentManager()
                       .beginTransaction()
                       .replace(R.id.container, fragment);

       if (addToBackstack) {
           transaction.addToBackStack(null);
       }

       transaction.commit();
   }
}

此活動會顯示 shr_main_activity.xml 中定義的 R.layout.shr_main_activity 版面配置檔案。

您可以從 onCreate(), MainActivity.java 中看到要顯示 LoginFragmentFragment 交易。LoginFragment. 這就是我們將在這個程式碼研究室中修改的內容。該活動也會實作 NavigationHost 中定義的 navigateTo(Fragment) 方法,讓任何片段都能前往其他片段。

在活動檔案中,按下 Command + 滑鼠鍵 (或 Control + 滑鼠) shr_main_activity 開啟版面配置檔案,或是前往 app -> res -> layout -> shr_main_activity.xml 的版面配置檔案。

shr_main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/container"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity" />

我們看到簡單的 <FrameLayout>,可做為活動顯示的任何片段的容器。請開啟 LoginFragment.java

LoginFragment.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;

/**
* Fragment representing the login screen for Shrine.
*/
public class LoginFragment extends Fragment {

   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment
       View view = inflater.inflate(R.layout.shr_login_fragment, container, false);

       // Snippet from "Navigate to the next Fragment" section goes here.

       return view;
   }

   // "isPasswordValid" from "Navigate to the next Fragment" section method goes here
}

LoginFragment 會加載 shr_login_fragment 版面配置檔案,並在 onCreateView() 中顯示。我們來看看 shr_login_fragment.xml 版面配置檔案,瞭解登入頁面的外觀。

shr_login_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@color/loginPageBackgroundColor"
   tools:context=".LoginFragment">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:clipChildren="false"
       android:clipToPadding="false"
       android:orientation="vertical"
       android:padding="24dp"
       android:paddingTop="16dp">

       <ImageView
           android:layout_width="64dp"
           android:layout_height="64dp"
           android:layout_gravity="center_horizontal"
           android:layout_marginTop="48dp"
           android:layout_marginBottom="16dp"
           app:srcCompat="@drawable/shr_logo" />

       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center_horizontal"
           android:layout_marginBottom="132dp"
           android:text="@string/shr_app_name"
           android:textAllCaps="true"
           android:textSize="16sp" />

       <!-- Snippet from "Add text fields" section goes here. -->

       <!-- Snippet from "Add buttons" section goes here. -->

   </LinearLayout>
</ScrollView>

這裡的 <LinearLayout> 頂端有一個 <ImageView>,代表「Shrine」標誌。

接著,您會看到代表「SHRINE」的 <TextView> 標記標籤。這個標籤的文字是名為 @string/shr_app_name字串資源。如果您透過 Command + 按一下 (或 Control + 按一下) 字串資源名稱,或是開啟 app -> res -> values -> strings.xml,就會看到已定義字串資源的 strings.xml 檔案。日後加入更多字串資源時,將會在這裡定義這些資源。這個檔案中的每個資源都應有 shr_ 前置字串,表示這些資源屬於 Shrine 應用程式的一部分。

現在您已熟悉範例程式碼,接下來讓我們來實作第一個元件。

3. 新增文字欄位

首先在登入頁面新增兩個文字欄位,讓使用者輸入使用者名稱和密碼。我們將使用 MDC 文字欄位元件,其中包含顯示浮動標籤和錯誤訊息的內建功能。

d83c47fb4aed3a82.png

新增 XML

shr_login_fragment.xml 中,在「SHRINE」下方的 <LinearLayout> 內新增兩個 TextInputLayout 元素,其中包含子項 TextInputEditText標籤 <TextView>

shr_login_fragment.xml

<com.google.android.material.textfield.TextInputLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_username">

   <com.google.android.material.textfield.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="text"
       android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
   android:id="@+id/password_text_input"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_password">

   <com.google.android.material.textfield.TextInputEditText
       android:id="@+id/password_edit_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>

上述程式碼片段代表兩個文字欄位,每個欄位均由 <TextInputLayout> 元素和 <TextInputEditText> 子項組成。每個文字欄位的提示文字是在 android:hint 屬性中指定。

我們已為文字欄位加入兩項新的字串資源:@string/shr_hint_username@string/shr_hint_password。開啟 strings.xml 即可查看這些字串資源。

strings.xml

...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...

新增輸入驗證功能

TextInputLayout 元件提供內建錯誤意見回饋功能。

如要顯示錯誤意見回饋,請對 shr_login_fragment.xml 進行下列變更:

  • 將「Password」(密碼) TextInputLayout 元素的 app:errorEnabled 屬性設為 true。這會在文字欄位下方,為錯誤訊息加入額外的邊框間距。
  • android:inputType 屬性設為「textPassword」在「密碼」 TextInputEditText元素中。即可隱藏密碼欄位的輸入文字。

經過變更後,shr_login_fragment.xml 中的文字欄位應如下所示:

shr_login_fragment.xml

<com.google.android.material.textfield.TextInputLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_username">

   <com.google.android.material.textfield.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="text"
       android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
   android:id="@+id/password_text_input"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="4dp"
   android:hint="@string/shr_hint_password"
   app:errorEnabled="true">

   <com.google.android.material.textfield.TextInputEditText
       android:id="@+id/password_edit_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>

現在請嘗試執行應用程式。您應該會看見一個頁面,其中有兩個文字欄位的「使用者名稱」欄位和「密碼」!

查看浮動標籤動畫:

333184b615aed4f7.gif

4. 新增按鈕

接著,我們會在登入頁面新增兩個按鈕:「取消」和「下一步」我們會使用 MDC Button 元件,這個元件內建經典的 Material Design 墨水漣漪特效。

4cb0c218948144b4.png

新增 XML

shr_login_fragment.xmlTextInputLayout 元素下方,將 <RelativeLayout> 新增至 <LinearLayout>。然後在 <RelativeLayout> 中新增兩個 <MaterialButton> 元素。

產生的 XML 檔案應如下所示:

shr_login_fragment.xml

<RelativeLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <com.google.android.material.button.MaterialButton
       android:id="@+id/next_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentEnd="true"
       android:layout_alignParentRight="true"
       android:text="@string/shr_button_next" />

   <com.google.android.material.button.MaterialButton
       android:id="@+id/cancel_button"
       style="@style/Widget.MaterialComponents.Button.TextButton"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginEnd="12dp"
       android:layout_marginRight="12dp"
       android:layout_toStartOf="@id/next_button"
       android:layout_toLeftOf="@id/next_button"
       android:text="@string/shr_button_cancel" />

</RelativeLayout>

大功告成!執行應用程式時,輕觸每個按鈕都會顯示墨水漣漪效果。

9dd162d65e4a92a2.gif

5. 前往下一個片段

最後,我們會在 LoginFragment.java 中新增一些 Java 程式碼,以連結「NEXT」另一個片段您會發現我們新增至版面配置的每個元件都有指派 id。我們會使用這些 id 參照程式碼中的元件,並新增一些錯誤檢查和導覽。

讓我們在 onCreateView() 底下的 LoginFragment.java 中新增私人布林值 isPasswordValid 方法,並使用邏輯判斷密碼是否有效。為了方便示範,我們只會確保密碼長度至少為 8 個字元:

LoginFragment.java

/*
   In reality, this will have more complex logic including, but not limited to, actual
   authentication of the username and password.
*/
private boolean isPasswordValid(@Nullable Editable text) {
   return text != null && text.length() >= 8;
}

接下來,將點擊事件監聽器新增至「Next」按鈕,可根據我們剛建立的 isPasswordValid() 方法設定及清除錯誤。在 onCreateView() 中,這個點擊事件監聽器應放置在 Inflater 行和 return view 行之間。

接著,讓我們在密碼 TextInputEditText 中新增按鍵事件監聽器,監聽會清除錯誤的重要事件。這個事件監聽器也應使用 isPasswordValid() 檢查密碼是否有效。您可以直接在 onCreateView() 中的點擊事件監聽器下方新增此方法。

您的 onCreateView() 方法現在應如下所示:

LoginFragment.java

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // Inflate the layout for this fragment
   View view = inflater.inflate(R.layout.shr_login_fragment, container, false);
   final TextInputLayout passwordTextInput = view.findViewById(R.id.password_text_input);
   final TextInputEditText passwordEditText = view.findViewById(R.id.password_edit_text);
   MaterialButton nextButton = view.findViewById(R.id.next_button);

   // Set an error if the password is less than 8 characters.
   nextButton.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
           if (!isPasswordValid(passwordEditText.getText())) {
               passwordTextInput.setError(getString(R.string.shr_error_password));
           } else {
               passwordTextInput.setError(null); // Clear the error
           }
       }
   });

   // Clear the error once more than 8 characters are typed.
   passwordEditText.setOnKeyListener(new View.OnKeyListener() {
       @Override
       public boolean onKey(View view, int i, KeyEvent keyEvent) {
           if (isPasswordValid(passwordEditText.getText())) {
               passwordTextInput.setError(null); //Clear the error
           }
           return false;
       }
   });
   return view;
}            

現在,我們可以前往另一個片段。錯誤驗證成功時,更新 onCreateView() 中的 OnClickListener,前往其他片段。如要完成此操作,請新增下列程式碼,前往 ProductGridFragment 到點擊事件監聽器的 else 案例:

LoginFragment.java

...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...

點擊事件監聽器現在應如下所示:

LoginFragment.java

...
MaterialButton nextButton = view.findViewById(R.id.next_button);

// Set an error if the password is less than 8 characters.
nextButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
       if (!isPasswordValid(passwordEditText.getText())) {
           passwordTextInput.setError(getString(R.string.shr_error_password));
       } else {
           passwordTextInput.setError(null); // Clear the error
           ((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
       }
   }
});
...

這一行新的程式碼會從 MainActivity 呼叫 navigateTo() 方法,前往新的片段 ProductGridFragment。目前這個空白頁面是在 MDC-102 中操作。

現在請建構應用程式。繼續按下「繼續」按鈕。

您做到了!這個畫面是下一個程式碼研究室的起點,您將在 MDC-102 中處理。

6. 全部完成

使用基本的 XML 標記和約 30 行的 Java 程式碼,Android 程式庫的 Material 元件可協助您建立符合 Material Design 指南的精美登入頁面,而且在所有裝置上的外觀和行為都一致。

後續步驟

文字欄位和按鈕是 MDC Android 程式庫中的兩個核心元件,但還有更多功能!您可以查看 MDC Android 的其他元件。或者,也可以參閱「MDC 102:Material Design 結構和版面配置」,瞭解頂端應用程式列、資訊卡檢視和格狀版面配置。感謝您試用 Material Design 元件。希望您喜歡本程式碼研究室!

我可以在合理的時間內,完成本程式碼研究室

非常同意 同意 普通 不同意 非常不同意

我想日後繼續使用 Material Design 元件

非常同意 同意 普通 不同意 非常不同意