Компоненты Material (MDC) помогают разработчикам реализовывать принципы Material Design. MDC, созданный командой инженеров и UX-дизайнеров Google, включает в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступен для Android, iOS, веб-приложений и Flutter. material.io/develop |
Что такое Material Design и Material Components для Android?
Material Design — это система для создания смелых и красивых цифровых продуктов. Объединяя стиль, брендинг, взаимодействие и анимацию в рамках единого набора принципов и компонентов, команды разработчиков могут максимально реализовать свой дизайнерский потенциал.
Для приложений Android Material Components for Android ( MDC Android ) объединяет дизайн и разработку с библиотекой компонентов для обеспечения согласованности во всем приложении. По мере развития системы Material Design эти компоненты обновляются, обеспечивая единообразную реализацию с точностью до пикселя и соответствие стандартам Google для фронтенд-разработки. MDC также доступен для веб-приложений, iOS и Flutter.
В этой лабораторной работе вы создадите страницу входа, используя несколько компонентов MDC Android.
Что вы построите
Эта лабораторная работа — первая из четырёх, которые помогут вам создать приложение Shrine — приложение электронной коммерции для Android, продающее одежду и товары для дома. В ней будет показано, как настроить компоненты под любой бренд или стиль с помощью MDC-Android.
В этой лабораторной работе вы создадите страницу входа для Shrine, которая будет содержать:
- Два текстовых поля: одно для ввода имени пользователя, другое для пароля
- Две кнопки: одна для «Отмена» и одна для «Далее»
- Название приложения (Shrine)
- Изображение логотипа Shrine
Компоненты Android MDC в этой лабораторной работе
- Текстовое поле
- Кнопка
Что вам понадобится
- Базовые знания разработки под Android
- Android Studio (загрузите здесь, если у вас ее еще нет)
- Эмулятор или устройство Android (доступно через Android Studio)
- Пример кода (см. следующий шаг)
Как бы вы оценили свой уровень опыта в создании приложений для Android?
Запустить Android Studio
При запуске Android Studio должно появиться окно с надписью «Добро пожаловать в Android Studio». Однако, если вы запускаете Android Studio впервые, следуйте инструкциям мастера установки Android Studio, используя значения по умолчанию . Загрузка и установка необходимых файлов может занять несколько минут, поэтому можете оставить его в фоновом режиме, пока вы работаете со следующим разделом.
Загрузите стартовое приложение Codelab
Стартовое приложение находится в каталоге 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
- После завершения работы мастера настройки и появления окна «Добро пожаловать в Android Studio» нажмите « Открыть существующий проект Android Studio» . Перейдите в каталог, куда был установлен пример кода, и выберите java -> shrine (или найдите на компьютере shrine ), чтобы открыть проект Shrine.
- Подождите немного, пока Android Studio выполнит сборку и синхронизацию проекта, на что указывают индикаторы активности в нижней части окна Android Studio.
- На этом этапе Android Studio может выдать ошибки сборки, поскольку у вас отсутствует Android SDK или инструменты сборки, например, показанные ниже. Следуйте инструкциям Android Studio, чтобы установить/обновить их и синхронизировать свой проект.
Добавить зависимости проекта
Проекту требуется зависимость от библиотеки поддержки MDC для Android . В загруженном примере кода эта зависимость уже должна быть указана, но для её обеспечения рекомендуется выполнить следующие шаги.
- Перейдите к файлу
build.gradle
модуляapp
и убедитесь, что блок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
для отображения фрагментов и навигации между ними.
Откройте MainActivity.java
в каталоге shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine
. Он должен содержать следующее:
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();
}
}
Это действие отображает файл макета R.layout.shr_main_activity
, определенный в shr_main_activity.xml
.
Видно, что в onCreate(),
MainActivity.java
запускает транзакцию Fragment
для отображения LoginFragment
. LoginFragment.
Именно его мы будем изменять в этой лабораторной работе. В активности также реализован метод navigateTo(Fragment)
, определённый в NavigationHost
, который позволяет любому фрагменту переходить к другому фрагменту.
Нажмите Command + Click (или Control + Click ) 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».
Далее следует тег <TextView>
, представляющий метку «SHRINE». Текст этой метки — строковый ресурс с именем @string/shr_app_name
. Если нажать Command + Click (или Control + Click ) на имя строкового ресурса или открыть app -> res -> values -> strings.xml
, можно увидеть файл strings.xml
, в котором определены строковые ресурсы. При добавлении дополнительных строковых ресурсов они будут определены здесь. Каждый ресурс в этом файле должен иметь префикс shr_
, указывающий на то, что он является частью приложения Shrine.
Теперь, когда вы знакомы с начальным кодом, давайте реализуем наш первый компонент.
Для начала добавим на страницу входа два текстовых поля для ввода имени пользователя и пароля. Мы будем использовать компонент MDC Text Field, который включает встроенную функцию отображения плавающей метки и сообщений об ошибках.
Добавьте XML
В shr_login_fragment.xml
добавьте два элемента TextInputLayout
с дочерним элементом TextInputEditText
внутри <LinearLayout>
под меткой «SHRINE» <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
:
- Установите атрибут
app:errorEnabled
в значение true для элемента PasswordTextInputLayout
. Это добавит дополнительный отступ для сообщения об ошибке под текстовым полем. - Установите атрибут
android:inputType
в значение "textPassword
" для элемента PasswordTextInputEditText
. Это скроет вводимый текст в поле пароля.
С этими изменениями текстовые поля в 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>
Теперь попробуйте запустить приложение. Вы увидите страницу с двумя текстовыми полями: «Имя пользователя» и «Пароль»!
Посмотрите на анимацию плавающей этикетки:
Далее мы добавим на страницу входа две кнопки: «Отмена» и «Далее». Мы будем использовать компонент MDC Button, в который встроен культовый эффект чернильной ряби в стиле Material Design.
Добавьте XML
В shr_login_fragment.xml
добавьте элемент <RelativeLayout>
к элементу <LinearLayout>
под элементами TextInputLayout
. Затем добавьте два элемента <MaterialButton>
к элементу <RelativeLayout>
.
Полученный 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>
Вот и всё! При запуске приложения при нажатии каждой кнопки будет появляться чернильная рябь.
Наконец, мы добавим код Java в LoginFragment.java
, чтобы подключить кнопку «ДАЛЕЕ» к другому фрагменту. Вы заметите, что каждому компоненту, добавленному в макет, присвоен id
. Мы будем использовать эти id
для ссылки на компоненты в нашем коде, а также для проверки ошибок и навигации.
Давайте добавим приватный логический метод isPasswordValid
в LoginFragment.java
под onCreateView()
с логикой для определения корректности пароля. Для целей этой демонстрации мы просто убедимся, что пароль содержит не менее 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;
}
Затем добавьте прослушиватель кликов к кнопке «Далее», который устанавливает и сбрасывает ошибку на основе метода 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;
}
Теперь мы можем перейти к другому фрагменту. Обновите OnClickListener
в onCreateView()
, чтобы перейти к другому фрагменту при успешной проверке ошибки. Это можно сделать, добавив следующую строку для перехода к 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
}
}
});
...
Эта новая строка кода вызывает метод navigateTo()
из MainActivity
для перехода к новому фрагменту — ProductGridFragment
. В настоящее время это пустая страница, с которой вы будете работать в MDC-102.
Теперь создайте приложение. Нажмите кнопку «Далее».
Вы справились! Этот экран станет отправной точкой нашей следующей лабораторной работы, над которой вы будете работать в MDC-102.
Используя базовую разметку XML и около 30 строк Java, библиотека Material Components для Android помогла вам создать красивую страницу входа, которая соответствует принципам Material Design, а также выглядит и ведет себя одинаково на всех устройствах.
Следующие шаги
Текстовое поле и кнопка — два основных компонента библиотеки MDC Android, но их гораздо больше! Вы можете изучить остальные компоненты MDC Android . Кроме того, ознакомьтесь с разделом MDC 102: Material Design Structure and Layout, чтобы узнать больше о верхней панели приложения, карточном представлении и сетке. Спасибо за знакомство с Material Components. Надеемся, вам понравилась эта практическая работа!