MDC-101 Android:材料元件 (MDC) 基本概念 (Kotlin)

logo_components_color_2x_web_96dp.png

質感元件 (MDC) 可協助開發人員實作質感設計。MDC 由 Google 的工程師和使用者體驗設計師團隊組成,提供數十種美觀且功能完善的 UI 元件,適用於 Android、iOS、網路和 Flutter。

material.io/develop

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

Material Design 是一個系統,能夠建構吸睛、美觀的數位產品。產品團隊將風格、品牌宣傳、互動和動作結合成一組一致的準則和元件,讓產品團隊發揮最佳設計潛力。

針對 Android 應用程式,Android 適用的 Material 元件(MDC Android) 結合了設計和工程設計,其中包含用來建立應用程式一致性的元件庫。隨著 Material Design 系統不斷演進,這些元件會隨之更新,確保像素的實作效果一致並符合 Google 的前端開發標準。網站、iOS 和 Flutter 也支援 MDC。

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

建構項目

本程式碼研究室是 4 個程式碼研究室的第一步,我們會引導您建立一個名為 Shrine 的應用程式。這個應用程式是電子商務 Android 應用程式,販售服飾和居家用品。它將示範如何使用 MDC Android 自訂任何元件,以反映任何品牌或樣式。

在這個程式碼研究室中,您將為神社建立登入頁面,其中包含:

  • 兩個文字欄位,一個用於輸入使用者名稱,另一個用於密碼
  • 兩個按鈕,一個代表「取消」,另一個則代表「下一步」。
  • 應用程式名稱 (Shrine)
  • 神社和圖片

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

  • 文字欄位
  • 按鈕

軟硬體需求

  • Android 開發基本知識
  • Android Studio (如果尚未下載,請按這裡下載)
  • Android 模擬器或裝置 (可透過 Android Studio 取得)
  • 範例程式碼 (請查看下一步)

您對於建構 Android 應用程式的體驗程度有多高?

初級 中級 專業

啟動 Android Studio

開啟 Android Studio 後,畫面上應該會顯示一個名稱為「歡迎使用 Android Studio」的視窗。不過,如果您是第一次啟動 Android Studio,請按照 Android Studio 設定精靈的步驟使用預設值。這個步驟可能需要幾分鐘才能下載並安裝必要的檔案,因此在進行下一個部分時,請在背景中保持執行。

下載新創公司程式碼研究室應用程式

下載入門應用程式

入門應用程式位於 material-components-android-codelabs-101-starter/kotlin 目錄中。

...或從 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. 設定精靈執行完畢後,系統會顯示「歡迎使用 Android Studio」視窗,請按一下 [開啟現有的 Android Studio 專案]。前往您安裝程式碼範例的目錄,然後選取 kotlin -> Shrine (或搜尋您的電腦以搜尋 shrine),即可開啟運送專案。
  2. 請等待 Android Studio 建立及同步處理專案,如 Android Studio 視窗底部的活動指標所示。
  3. 目前,Android Studio 可能會引發部分建構錯誤,原因是您缺少 Android SDK 或建構工具,例如下列工具。按照 Android Studio 中的操作說明安裝/更新這些設定,並且同步處理您的專案。

新增專案依附元件

專案必須依附於 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. 按下綠色的 [執行 / 播放] 按鈕,即可建構並執行應用程式。
  3. 在「選取部署目標」視窗中,如果您的可用裝置已列出 Android 裝置,請跳到步驟 8。否則,請按一下 [Create New Virtual Device]
  4. 在「選取硬體」畫面中,選取手機 (例如 Pixel 2),然後點選 [下一步]
  5. 在「System Image」(系統映像檔) 畫面中,選取最新的 Android 版本 (最好是最高的 API 等級)。如果尚未安裝,請點選顯示的 [下載] 連結並完成下載
  6. 按一下「Next」(下一步)
  7. 在「Android Virtual Device (AVD)」(Android 虛擬裝置 (AVD)) 畫面中,保留原設定,然後按一下 [完成]
  8. 從部署目標對話方塊中選取 Android 裝置
  9. 按一下 [OK] (確定)。
  10. Android Studio 會建置及部署應用程式,並在目標裝置上自動開啟該應用程式。

完成了,你的模擬器登入頁面應使用模擬器的起始程式碼。你應該會看到「Shrine」這個名字和下方下方的神社標誌。

我們來檢查程式碼。我們已經在程式碼範例中提供了簡單的 Fragment 導覽架構,以顯示片段並瀏覽片段。

shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.kotlin.shrine 目錄中開啟 MainActivity.kt。內容如下:

MainActivity.kt

package com.google.codelabs.mdc.kotlin.shrine

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

class MainActivity : AppCompatActivity(), NavigationHost {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.shr_main_activity)

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

   override fun navigateTo(fragment: Fragment, addToBackstack: Boolean) {
       val transaction = supportFragmentManager
               .beginTransaction()
               .replace(R.id.container, fragment)

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

       transaction.commit()
   }
}

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

如您見到,onCreate(), MainActivity.kt 會進行 Fragment 交易,以便顯示 LoginFragment。此程式碼研究室將修改 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.kt」。

LoginFragment.kt

package com.google.codelabs.mdc.kotlin.shrine

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

class LoginFragment : Fragment() {

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment
       val view = inflater.inflate(R.layout.shr_login_fragment, container, false)

       return view
   }
}

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" />
   </LinearLayout>
</ScrollView>

這裡可以看到 <LinearLayout> 的「<ImageView>」上方,代表神社標誌。

之後,標誌下方會顯示 <TextView> 標記,代表神社標籤。這個標籤的文字是名為 @string/shr_app_name字串資源。如果您按住 Command + Click (或 Control + Click) 字串資源名稱,或開啟 app -> res -> values -> strings.xml,即可查看定義字串資源的 strings.xml 檔案。日後只要加入更多字串資源,即可在這裡定義。這個檔案中的每個資源都應加上 shr_ 前置字串,表示這些路徑屬於「神社」應用程式。

現在您已經熟悉入門程式碼了,接著讓我們開始實作第一個元件。

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

新增 XML

shr_login_fragment.xml 中,在 <LinearLayout> 下方的「SHRINE」標籤底下新增含有兩個 TextInputEditTextTextInputLayout 元素。標籤 <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" />
</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。系統會在文字欄位下方為錯誤訊息加入額外的填充字元。
  • 在「Password (密碼)」TextInputEditText 元素中,將 android:inputType 屬性設為「textPassword」。這項操作會隱藏密碼欄位中的輸入文字。

推出變更後,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" />
</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>

現在請嘗試執行應用程式。您應該會看到一個頁面,其中有「Username」和「Password」這兩個文字欄位!

查看浮動標籤動畫:

接著,在登入頁面加入兩個按鈕:「&&t;取消」和「下一步」。我們將使用內建 Material Design 油墨波紋效果的 MDC 按鈕元件。

新增 XML

shr_login_fragment.xml 中,在 <LinearLayout>TextInputLayout 元素下方新增 <RelativeLayout>。接著,在 <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>

大功告成!執行應用程式時,輕觸每個按鈕時,會顯示墨水波紋。

最後,我們會將一些 Kotlin 程式碼新增至 LoginFragment.kt,以連結「下一個」按鈕,以便轉換為其他片段。

允許在 LoginFragment.ktLoginFragment.kt 中新增私人布林值 isPasswordValid 方法 (透過邏輯判斷密碼是否有效)。在此示範中,我們會確保密碼長度至少包含 8 個字元:

LoginFragment.kt

private fun isPasswordValid(text: Editable?): Boolean {
   return text != null && text.length >= 8
}

接著,在「下一步」按鈕中新增點擊事件監聽器,讓系統根據剛剛建立的 isPasswordValid() 方法設定及清除錯誤。在 onCreateView() 中,點擊事件監聽器應置於內嵌線和 return view 行之間。

現在,請在密碼 TextInputEditText 中加入一個主要監聽器,以聽取可清除錯誤的金鑰事件。這個接聽程式也應該使用 isPasswordValid() 來檢查密碼是否有效。您可以直接在 onCreateView() 的點擊監聽器下方新增這項資訊。

您的 onCreateView() 方法現在看起來應該像這樣:

LoginFragment.kt

override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment.
       val view = inflater.inflate(R.layout.shr_login_fragment, container, false)

       // Set an error if the password is less than 8 characters.
       view.next_button.setOnClickListener({
           if (!isPasswordValid(password_edit_text.text!!)) {
               password_text_input.error = getString(R.string.shr_error_password)
           } else {
               // Clear the error.
               password_text_input.error = null
           }
       })

       // Clear the error once more than 8 characters are typed.
       view.password_edit_text.setOnKeyListener({ _, _, _ ->
           if (isPasswordValid(password_edit_text.text!!)) {
               // Clear the error.
               password_text_input.error = null
           }
           false
       })

       return view
   }
}

現在,我們可以前往另一個片段。在 onCreateView() 中,更新 OnClickListener 以在驗證成功後前往其他片段。你的 clickListener 程式碼現在應如下所示:

LoginFragment.kt

// Set an error if the password is less than 8 characters.
view.next_button.setOnClickListener({
   if (!isPasswordValid(password_edit_text.text!!)) {
       password_text_input.error = getString(R.string.shr_error_password)
   } else {
       // Clear the error.
       password_text_input.error = null
       // Navigate to the next Fragment.
       (activity as NavigationHost).navigateTo(ProductGridFragment(), false)
   }
})

我們已在點擊接聽器的 else 案例中加入 (activity as NavigationHost).navigateTo(ProductGridFragment(), false) 行。這行從 MainActivity 呼叫 navigateTo() 方法可瀏覽至新的片段 -- ProductGridFragment。目前這是空白頁面,供您在 MDC-102 中使用。

現在,請建置應用程式。請按 [下一步] 按鈕

您成功了!這個畫面將是下一個程式碼研究室的起點,供您在 MDC-102 中使用。

透過 Android 專用的 Material Components 程式庫,您可以使用基本 XML 標記和約 30 行的 Kotlin 標記,建立符合 Material Design 規範的精美登入頁面,並確保各種裝置都能維持一致的外觀與行為。

後續步驟

文字欄位和按鈕是 MDC Android 程式庫中的兩個核心元件,不過還有許多其他用途!您可以查看其他 MDC Android 元件。或者,您也可以參閱 MDC 102:質感設計結構和版面配置,瞭解熱門應用程式列、資訊卡檢視和格狀版面配置。感謝您試用 Material Components。希望您喜歡這個程式碼研究室!

我以合理的時間和心力完成了這個程式碼研究室

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

我要在日後繼續使用 Material Components

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