1. 简介
Material Components (MDC) 有助于开发者实现 Material Design。MDC 是由一组 Google 工程师和用户体验设计人员倾心打造的,提供数十种精美实用的界面组件,可用于 Android、iOS、Web 和 Flutter.material.io/develop |
什么是 Material Design 和 Material Components for Android?
Material Design 是一个系统,用于构建醒目、美观的数字产品。通过采用一套一致的原则和组件将样式、品牌、交互和动效结合起来,产品团队能够充分发挥其设计潜能。
对于 Android 应用,适用于 Android 的 Material 组件 (MDC Android) 将设计和工程与组件库相结合,以在应用内实现一致性。随着 Material Design 系统不断发展,这些组件会进行更新,从而可确保一致且每个像素都无比完美的实现,并确保遵循 Google 的前端开发标准。MDC 也适用于 Web、iOS 和 Flutter。
在此 Codelab 中,您将使用 MDC Android 的若干组件构建一个登录页面。
您将构建的内容
我们提供了 4 个 Codelab 来引导您构建一款名为 Shrine 的应用,这是其中的第 1 个。Shrine 是一个销售服装和家居用品的电子商务 Android 应用。本文将演示如何使用 MDC-Android 自定义组件以反映任何品牌或风格。
在此 Codelab 中,您将为 Shrine 构建一个包含以下内容的登录页面:
- 两个文本字段,分别用于输入用户名和密码
- 两个按钮,分别对应“Cancel”(取消)和“Next”(下一步)
- 应用名称 (Shrine)
- Shrine 徽标的图片
本 Codelab 中用到的 MDC Android 组件
- 文本字段
- 按钮
所需条件
- 已掌握 Android 开发方面的基础知识
- Android Studio(如果尚未安装,请在此处下载)
- Android 模拟器或设备(可通过 Android Studio 获取)
- 示例代码(参见下一步)
您如何评价自己在构建 Android 应用方面的经验水平?
<ph type="x-smartling-placeholder">2. 设置您的开发环境
启动 Android Studio
打开 Android Studio 后,您应该会看到一个标题为“Welcome to Android Studio”的窗口。不过,如果这是您第一次启动 Android Studio,请使用默认值完成 Android Studio 设置向导中的步骤。该步骤可能需要几分钟时间才能下载并安装必要的文件,因此您可以让其在后台运行,同时继续执行下一部分的操作。
下载起始 Codelab 应用
起始应用位于 material-components-android-codelabs-101-starter/java
目录中。
…或从 GitHub 克隆
如需从 GitHub 克隆此 Codelab,请运行以下命令:
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(或在计算机中搜索 shrine),以打开 Shrine 项目。
- 稍等片刻,让 Android Studio 构建和同步项目,如 Android Studio 窗口底部的 activity 指示器所示。
- 此时,由于缺少 Android SDK 或构建工具,因此 Android Studio 可能会显示一些构建错误(如下所示)。按照 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
导航框架,用于显示 fragment 以及在 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();
}
}
此 activity 会显示 shr_main_activity.xml
中定义的 R.layout.shr_main_activity
布局文件。
您可以看到,在 onCreate(),
中,MainActivity.java
启动了 Fragment
事务,以显示 LoginFragment
。LoginFragment.
这就是我们将在此 Codelab 中修改的内容。该 activity 还实现了一个在 NavigationHost
中定义的 navigateTo(Fragment)
方法,可让任何 fragment 转到其他 fragment。
按住 Command 键的同时点击(或按住 Ctrl 键的同时点击)该 activity 文件中的 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>
,充当 activity 所显示 fragment 的容器。我们打开 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>
在这里,我们可以看到一个顶部带有 <ImageView>
的 <LinearLayout>
,表示“Shrine”徽标。
在此之后,有一个代表“SHRINE”标签的 <TextView>
标记。此标签的文本是一个名为 @string/shr_app_name
的字符串资源。如果您在按住 Command 键的同时点击(或按住 Ctrl 键的同时点击)该字符串资源名称,或者打开 app -> res -> values -> strings.xml
,则可看到其中定义了字符串资源的 strings.xml
文件。以后添加更多字符串资源时,将在此处进行定义。此文件中的每个资源都应带有 shr_
前缀,以指明它们是 Shrine 应用的一部分。
现在,您已经熟悉了起始代码,接下来我们要实现第一个组件。
3. 添加文本字段
首先,我们将为登录页面添加两个文本字段,供用户输入用户名和密码。我们将使用 MDC 文本字段组件,其中包括可显示浮动标签和错误消息的内置功能。
添加 XML
在 shr_login_fragment.xml
中,在 <LinearLayout>
内的“SHRINE”标签 <TextView>
的下方,添加两个包含子元素 TextInputEditText
的 TextInputLayout
元素:
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。这会为文本字段下方的错误消息添加额外的内边距。 - 对于 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"
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>
现在,请尝试运行该应用。您应该会看到一个包含两个文本字段(“Username”和“Password”)的页面!
查看悬浮标签动画:
4. 添加按钮
接下来,我们将为登录页面添加两个按钮:“Cancel”和“Next”。我们将使用 MDC 按钮组件,该组件内置了标志性的 Material Design 水墨涟漪效果。
添加 XML
在 shr_login_fragment.xml
中,将 <RelativeLayout>
添加到 TextInputLayout
元素下方的 <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. 转到下一个 fragment
最后,我们将向 LoginFragment.java
添加一些 Java 代码,以连接“NEXT”按钮添加到另一个 fragment。您会发现,我们添加到布局中的每个组件都分配了一个 id
。我们将使用这些 id
引用代码中的组件,并添加一些错误检查和导航。
让我们在 LoginFragment.java
中的 onCreateView()
下添加一个私有布尔值 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()
中,此点击监听器应放置在膨胀器代码行和 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;
}
现在,我们可以导航到另一个 fragment。更新 onCreateView()
中的 OnClickListener
,以便在错误验证成功时导航到另一个 fragment。为此,您可以添加以下代码行,以将 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()
方法,以导航到新的 fragment - ProductGridFragment
。目前,这是一个空白页面,您将在 MDC-102 中完善此页面。
现在,构建应用。接下来,请按“Next”按钮。
大功告成!此屏幕是我们下一个 Codelab 的起点,您将在 MDC-102 中继续使用它。
6. 大功告成
借助基本的 XML 标记和约 30 行 Java 代码,Material Components for Android 库就可以帮助您创建一个符合 Material Design 准则的精美登录页面,同时让该页面在所有设备上保持一致的外观和行为。
后续步骤
文本字段和按钮是 MDC Android 库的两个核心组件,但该库还提供了许多其他组件!您可以在 MDC Android 中探索其余组件。或者,前往 MDC 102:Material Design 结构和布局,了解顶部应用栏、卡片视图和网格布局。感谢您试用 Material Components。希望您喜欢此 Codelab!