1. Giới thiệu
Thành phần Material (MDC) giúp nhà phát triển triển khai Material Design. Được tạo bởi một nhóm các kỹ sư và nhà thiết kế trải nghiệm người dùng tại Google, MDC có nhiều thành phần giao diện người dùng đẹp mắt, dễ sử dụng và có sẵn cho Android, iOS, web và Flutter.material.io/develop |
Material Design và Material Components cho Android là gì?
Material Design là hệ thống để tạo các sản phẩm kỹ thuật số đẹp mắt và ấn tượng. Bằng cách hợp nhất phong cách, cách xây dựng thương hiệu, sự tương tác và chuyển động theo một bộ nguyên tắc và thành phần nhất quán, các nhóm phụ trách sản phẩm có thể phát hiện ra tiềm năng thiết kế lớn nhất của họ.
Đối với các ứng dụng Android, Material Components cho Android (MDC Android) hợp nhất thiết kế và kỹ thuật với một thư viện thành phần nhằm tạo ra sự nhất quán trên ứng dụng của bạn. Khi hệ thống Material Design phát triển, các thành phần này cũng được cập nhật để đảm bảo việc triển khai pixel một cách hoàn hảo và tuân thủ các tiêu chuẩn phát triển giao diện người dùng của Google. MDC cũng được cung cấp cho web, iOS và Flutter.
Trong lớp học lập trình này, bạn sẽ xây dựng một trang đăng nhập bằng cách sử dụng một số thành phần của MDC Android.
Sản phẩm bạn sẽ tạo ra
Lớp học lập trình này là lớp học đầu tiên trong số 4 lớp học lập trình sẽ hướng dẫn bạn cách xây dựng một ứng dụng có tên Shrine, một ứng dụng Android thương mại điện tử chuyên bán quần áo và đồ gia dụng. Bản trình bày này sẽ minh hoạ cách bạn có thể tuỳ chỉnh các thành phần để phản ánh bất kỳ thương hiệu hoặc phong cách nào bằng MDC-Android.
Trong lớp học lập trình này, bạn sẽ xây dựng một trang đăng nhập cho Đền chứa:
- Hai trường văn bản, một trường để nhập tên người dùng và trường còn lại để nhập mật khẩu
- Hai nút, một nút cho thao tác "Huỷ" và một cho "Tiếp theo"
- Tên ứng dụng (Đền)
- Hình ảnh biểu trưng của Đền thờ
Các thành phần Android MDC trong lớp học lập trình này
- Trường văn bản
- Nút
Bạn cần có
- Kiến thức cơ bản về phát triển Android
- Android Studio (tải xuống tại đây nếu bạn chưa có)
- Trình mô phỏng hoặc thiết bị Android (có trên Android Studio)
- Mã mẫu (xem bước tiếp theo)
Bạn đánh giá mức độ kinh nghiệm xây dựng ứng dụng Android của mình ở mức nào?
2. Thiết lập môi trường phát triển
Khởi động Android Studio
Khi mở Android Studio, bạn sẽ thấy cửa sổ có tiêu đề "Welcome to Android Studio" (Chào mừng bạn đến với Android Studio). Tuy nhiên, nếu đây là lần đầu tiên bạn chạy Android Studio, hãy làm theo các bước trong Android Studio Setup Wizard (Trình hướng dẫn thiết lập Android Studio) với các giá trị mặc định. Bước này có thể mất vài phút để tải xuống và cài đặt các tệp cần thiết, vì vậy hãy để ứng dụng này chạy dưới nền trong khi thực hiện phần tiếp theo.
Tải ứng dụng khởi đầu của lớp học lập trình
Ứng dụng khởi đầu này nằm trong thư mục material-components-android-codelabs-101-starter/java
.
...hoặc sao chép tệp trên GitHub
Để sao chép lớp học lập trình này từ GitHub, hãy chạy các lệnh sau:
git clone https://github.com/material-components/material-components-android-codelabs cd material-components-android-codelabs/ git checkout 101-starter
Tải mã khởi đầu trong Android Studio
- Sau khi trình hướng dẫn thiết lập hoàn tất và cửa sổ Welcome to Android Studio (Chào mừng bạn đến với Android Studio) hiển thị, hãy nhấp vào Open an existing Android Studio project (Mở một dự án Android Studio hiện có). Chuyển đến thư mục mà bạn đã cài đặt mã mẫu và chọn java -> đền thờ (hoặc tìm điện thờ trên máy tính) để mở dự án Đền thờ.
- Đợi một chút để Android Studio tạo và đồng bộ hoá dự án, như được minh hoạ bằng các chỉ báo hoạt động ở cuối cửa sổ Android Studio.
- Tại thời điểm này, Android Studio có thể phát sinh một số lỗi bản dựng do bạn đang thiếu SDK Android hoặc công cụ xây dựng, chẳng hạn như lỗi hiển thị dưới đây. Làm theo hướng dẫn trong Android Studio để cài đặt/cập nhật các ứng dụng này và đồng bộ hoá dự án của bạn.
Thêm phần phụ thuộc của dự án
Dự án cần phần phụ thuộc trên thư viện hỗ trợ Android MDC. Mã mẫu bạn tải xuống đã liệt kê phần phụ thuộc này, nhưng bạn nên thực hiện các bước sau đây để đảm bảo phần phụ thuộc này.
- Chuyển đến tệp
build.gradle
của mô-đunapp
và đảm bảo rằng khốidependencies
chứa phần phụ thuộc trên MDC Android:
api 'com.google.android.material:material:1.1.0-alpha06'
- (Không bắt buộc) Nếu cần, hãy chỉnh sửa tệp
build.gradle
để thêm các phần phụ thuộc sau đây rồi đồng bộ hoá dự án.
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' }
Chạy ứng dụng khởi đầu
|
Thành công! Mã khởi đầu cho trang đăng nhập của Đền phải chạy trong trình mô phỏng. Bạn sẽ thấy tên "Thuỳ" và biểu trưng Đền thờ ngay bên dưới.
Hãy cùng xem xét mã. Chúng tôi đã cung cấp một khung điều hướng Fragment
đơn giản trong mã mẫu để hiển thị các mảnh và di chuyển giữa các mảnh.
Mở MainActivity.java
trong thư mục shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine
. Mã này phải có:
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();
}
}
Hoạt động này làm hiện tệp bố cục R.layout.shr_main_activity
, được xác định trong shr_main_activity.xml
.
Bạn có thể thấy rằng trong onCreate(),
, MainActivity.java
sẽ bắt đầu một giao dịch Fragment
để cho thấy LoginFragment
. LoginFragment.
Đó là nội dung chúng ta sẽ sửa đổi trong lớp học lập trình này. Hoạt động này cũng triển khai phương thức navigateTo(Fragment)
, được xác định trong NavigationHost
, cho phép mọi mảnh điều hướng đến một mảnh khác.
Command + Nhấp (hoặc Control + Nhấp) shr_main_activity
trong tệp hoạt động để mở tệp bố cục hoặc chuyển đến tệp bố cục trong 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" />
Ở đây, chúng ta thấy một <FrameLayout>
đơn giản đóng vai trò là vùng chứa dành cho mọi mảnh mà hoạt động hiển thị. Hãy mở 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
tăng cường tệp bố cục shr_login_fragment
và hiển thị tệp đó trong onCreateView()
. Hãy xem tệp bố cục shr_login_fragment.xml
để hình dung trang đăng nhập sẽ có giao diện như thế nào.
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>
Ở đây, chúng ta có thể thấy <LinearLayout>
có <ImageView>
ở trên cùng, thể hiện "Thần" biểu trưng.
Theo đó, có một thẻ <TextView>
đại diện cho "SHRINE" . Văn bản của nhãn này là một tài nguyên chuỗi có tên @string/shr_app_name
. Nếu bạn nhấn tổ hợp phím Command + Nhấp (hoặc Control + Nhấp) vào tên tài nguyên chuỗi hoặc mở app -> res -> values -> strings.xml
, bạn có thể thấy tệp strings.xml
trong đó tài nguyên chuỗi được xác định. Khi các tài nguyên chuỗi khác được thêm trong tương lai, các tài nguyên đó sẽ được xác định tại đây. Mọi tài nguyên trong tệp này phải có tiền tố shr_
để cho biết rằng chúng thuộc ứng dụng Shrine.
Giờ bạn đã quen với mã khởi đầu, hãy triển khai thành phần đầu tiên.
3. Thêm trường văn bản
Để bắt đầu, chúng tôi sẽ thêm hai trường văn bản vào trang đăng nhập để mọi người nhập tên người dùng và mật khẩu của họ. Chúng ta sẽ sử dụng thành phần Trường văn bản MDC, bao gồm chức năng tích hợp sẵn để hiển thị nhãn nổi và thông báo lỗi.
Thêm tệp XML
Trong shr_login_fragment.xml
, hãy thêm 2 phần tử TextInputLayout
có phần tử con TextInputEditText
ở bên trong <LinearLayout>
, bên dưới mục "SHRINE" nhãn <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>
Đoạn mã trên đại diện cho 2 trường văn bản, mỗi trường bao gồm một phần tử <TextInputLayout>
và một phần tử con <TextInputEditText>
. Văn bản gợi ý cho từng trường văn bản được chỉ định trong thuộc tính android:hint
.
Chúng tôi đã thêm hai tài nguyên chuỗi mới cho trường văn bản – @string/shr_hint_username
và @string/shr_hint_password
. Mở strings.xml
để xem các tài nguyên chuỗi này.
strings.xml
...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...
Thêm phương thức xác thực dữ liệu đầu vào
Các thành phần TextInputLayout
cung cấp chức năng phản hồi về lỗi tích hợp sẵn.
Để hiển thị phản hồi về lỗi, hãy thực hiện các thay đổi sau đối với shr_login_fragment.xml
:
- Đặt thuộc tính
app:errorEnabled
thành true trên phần tử PasswordTextInputLayout
. Thao tác này sẽ thêm khoảng đệm bổ sung cho thông báo lỗi bên dưới trường văn bản. - Đặt thuộc tính
android:inputType
thành "textPassword
" trên phần tử PasswordTextInputEditText
. Thao tác này sẽ ẩn văn bản nhập trong trường mật khẩu.
Với những thay đổi này, các trường văn bản trong shr_login_fragment.xml
sẽ có dạng như sau:
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>
Bây giờ, hãy thử chạy ứng dụng. Bạn sẽ thấy một trang có hai trường văn bản cho "Tên người dùng" và "Mật khẩu"!
Xem ảnh động nhãn nổi:
4. Thêm nút
Tiếp theo, chúng ta sẽ thêm hai nút vào trang đăng nhập: "Huỷ" và "Tiếp theo". Chúng ta sẽ sử dụng thành phần Nút MDC, tích hợp sẵn hiệu ứng gợn sóng mực của Material Design mang tính biểu tượng.
Thêm tệp XML
Trong shr_login_fragment.xml
, hãy thêm <RelativeLayout>
vào <LinearLayout>
, bên dưới các phần tử TextInputLayout
. Sau đó, hãy thêm 2 phần tử <MaterialButton>
vào <RelativeLayout>
.
Tệp XML kết quả sẽ có dạng như sau:
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>
Vậy là xong! Khi bạn chạy ứng dụng, một gợn sóng sẽ xuất hiện khi bạn nhấn vào từng nút.
5. Chuyển đến mảnh tiếp theo
Cuối cùng, chúng ta sẽ thêm một số mã Java vào LoginFragment.java
để kết nối "TIẾP THEO" của chúng ta sang một phân đoạn khác. Bạn sẽ nhận thấy rằng mỗi thành phần chúng ta đã thêm vào bố cục đều được gán một id
. Chúng ta sẽ sử dụng các id
này để tham chiếu đến các thành phần trong mã, đồng thời bổ sung một số bước kiểm tra và điều hướng lỗi.
Hãy thêm phương thức isPasswordValid
boolean riêng tư trong LoginFragment.java
bên dưới onCreateView()
, với logic để xác định xem mật khẩu có hợp lệ hay không. Đối với bản minh hoạ này, chúng tôi sẽ chỉ đảm bảo rằng mật khẩu dài ít nhất 8 ký tự:
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;
}
Tiếp theo, hãy thêm một trình nghe lượt nhấp vào lệnh "Tiếp theo" nút đặt và xoá lỗi dựa trên phương thức isPasswordValid()
mà chúng ta vừa tạo. Trong onCreateView()
, trình nghe lượt nhấp này phải được đặt giữa dòng tăng cường và dòng return view
.
Tiếp theo, hãy thêm một trình nghe phím vào mật khẩu TextInputEditText
để theo dõi các sự kiện chính giúp xoá lỗi. Trình nghe này cũng nên sử dụng isPasswordValid()
để kiểm tra xem mật khẩu có hợp lệ hay không. Bạn có thể thêm đoạn mã này ngay bên dưới trình nghe lượt nhấp trong onCreateView()
.
Bây giờ, phương thức onCreateView() sẽ có dạng như sau:
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;
}
Bây giờ, chúng ta có thể điều hướng đến một mảnh khác. Cập nhật OnClickListener
trong onCreateView()
để chuyển đến một mảnh khác khi xác thực lỗi thành công. Bạn có thể thực hiện việc này bằng cách thêm dòng sau để chuyển đến ProductGridFragment
vào trường hợp else
của trình nghe lượt nhấp:
LoginFragment.java
...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...
Bây giờ, trình nghe lượt nhấp của bạn sẽ có dạng như sau:
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
}
}
});
...
Dòng mã mới này gọi phương thức navigateTo()
từ MainActivity
để điều hướng đến một mảnh mới – ProductGridFragment
. Hiện tại, trang này trống mà bạn sẽ xử lý trong MDC-102.
Bây giờ, hãy xây dựng ứng dụng. Hãy tiếp tục và nhấn nút Tiếp theo.
Các bạn đã làm được! Màn hình này sẽ là điểm xuất phát của lớp học lập trình tiếp theo mà bạn sẽ thực hiện trong MDC-102.
6. Đã xong
Sử dụng mã đánh dấu XML cơ bản và khoảng 30 dòng Java, Thư viện Material Components cho Android đã giúp bạn tạo ra một trang đăng nhập đẹp mắt, tuân thủ các nguyên tắc của Material Design, đồng thời có giao diện và hoạt động nhất quán trên mọi thiết bị.
Các bước tiếp theo
Trường văn bản và Nút là 2 thành phần cốt lõi trong thư viện Android MDC, nhưng còn nhiều thành phần khác nữa! Bạn có thể khám phá các thành phần còn lại trong MDC Android. Bạn cũng có thể truy cập MDC 102: Material Design Structure and Layout (Cấu trúc và bố cục Material Design) để tìm hiểu về thanh ứng dụng trên cùng, chế độ xem thẻ và bố cục lưới. Cảm ơn bạn đã dùng thử Thành phần Material. Chúng tôi hy vọng bạn thích lớp học lập trình này!