1. 簡介
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)
- 神殿的標誌圖片
本程式碼研究室中的 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 中載入範例程式碼
- 設定精靈完成後,系統顯示「Welcome to Android Studio」視窗,請按一下「Open an existing Android Studio project」。前往您安裝程式碼範例的目錄,然後選取 java ->神社 (或在電腦上搜尋小時) 以開啟 Shrine 專案。
- 等待 Android Studio 建構並同步處理專案,如 Android Studio 視窗底部的活動指標所示。
- 此時,Android Studio 可能會引發部分建構錯誤,因為缺少 Android SDK 或建構工具 (如下所示)。請按照 Android Studio 中的指示安裝/更新這些套件,並同步處理專案。
新增專案依附元件
專案需要使用 MDC Android 支援資料庫的依附元件。您下載的程式碼範例中應該已經包含這個依附元件,但建議您執行下列步驟確認。
- 前往
app
模組的build.gradle
檔案,確認dependencies
區塊包含 MDC Android 的依附元件:
api 'com.google.android.material:material:1.1.0-alpha06'
- (選用) 如有需要,請編輯
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' }
執行範例應用程式
|
大功告成!Shrine 登入頁面的範例程式碼應會在模擬器中執行。您應該會看到「Shrine」這個名稱旁邊還有 Shrine 標誌
我們來看看程式碼。我們在程式碼範例中提供簡易的 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
中看到要顯示 LoginFragment
的 Fragment
交易。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 文字欄位元件,其中包含顯示浮動標籤和錯誤訊息的內建功能。
新增 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>
現在請嘗試執行應用程式。您應該會看見一個頁面,其中有兩個文字欄位的「使用者名稱」欄位和「密碼」!
查看浮動標籤動畫:
4. 新增按鈕
接著,我們會在登入頁面新增兩個按鈕:「取消」和「下一步」我們會使用 MDC Button 元件,這個元件內建經典的 Material Design 墨水漣漪特效。
新增 XML
在 shr_login_fragment.xml
的 TextInputLayout
元素下方,將 <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>
大功告成!執行應用程式時,輕觸每個按鈕都會顯示墨水漣漪效果。
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 元件。希望您喜歡本程式碼研究室!