MDC-101 Android: основы материальных компонентов (MDC) (Java)

1. Введение

logo_components_color_2x_web_96dp.png

Компоненты Material (MDC) помогают разработчикам внедрять Material Design. Созданные командой инженеров и UX-дизайнеров Google, MDC включают в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступны для 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)
  • Изображение логотипа храма

4cb0c218948144b4.png

Компоненты MDC для Android в этом практическом занятии.

  • Текстовое поле
  • Кнопка

Что вам понадобится

  • Базовые знания разработки под Android.
  • Android Studio (скачайте её здесь, если у вас её ещё нет).
  • Эмулятор или устройство Android (доступное через Android Studio)
  • Пример кода (см. следующий шаг)

Как бы вы оценили свой уровень опыта в разработке Android-приложений?

Новичок Средний Профессионал

2. Настройте среду разработки.

Запустите 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.

  1. После завершения работы мастера установки и появления окна «Добро пожаловать в Android Studio» нажмите « Открыть существующий проект Android Studio» . Перейдите в каталог, где вы установили примеры кода, и выберите java -> shrine (или найдите shrine на своем компьютере), чтобы открыть проект Shrine.
  2. Подождите немного, пока Android Studio соберет и синхронизирует проект, как это отобразится в индикаторах активности в нижней части окна Android Studio.
  3. На этом этапе Android Studio может выдавать ошибки сборки, поскольку у вас отсутствует Android SDK или инструменты сборки, например, показанные ниже. Следуйте инструкциям в Android Studio, чтобы установить/обновить их и синхронизировать ваш проект.

F5H6srsw_5xOPGFpKrm1RwgewatxA_HUbDI1PWoQUAoJcT6DpfBOkAYwq3S-2vUHvweUa FgAmG7BtUKkGouUbhTwXQh53qec8tO5eVecdlo7QIoLc8rNxFEBb8l7RlS-KzBbZOzVhA

Добавьте зависимости проекта

Проекту необходима зависимость от библиотеки поддержки Android MDC . В загруженном вами примере кода эта зависимость уже должна быть указана, но для уверенности рекомендуется выполнить следующие шаги.

  1. Перейдите к файлу build.gradle модуля app и убедитесь, что блок 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. Убедитесь, что конфигурация сборки слева от кнопки «Запуск/Воспроизведение» — это app .
  2. Нажмите зеленую кнопку «Запустить/Играть» , чтобы собрать и запустить приложение.
  3. В окне «Выбор целевого устройства развертывания» , если у вас уже есть устройство Android в списке доступных устройств, перейдите к шагу 8. В противном случае нажмите «Создать новое виртуальное устройство» .
  4. На экране «Выбор оборудования» выберите телефонное устройство, например Pixel 2 , а затем нажмите «Далее» .
  5. На экране «Образ системы» выберите последнюю версию Android , предпочтительно с самым высоким уровнем API. Если она не установлена, нажмите на появившуюся ссылку «Загрузить» и завершите загрузку.
  6. Нажмите «Далее» .
  7. На экране «Виртуальное устройство Android (AVD)» оставьте настройки без изменений и нажмите «Готово» .
  8. Выберите устройство Android в диалоговом окне выбора целевого устройства для развертывания.
  9. Нажмите «ОК» .
  10. Android Studio собирает приложение, развертывает его и автоматически открывает на целевом устройстве.

Успех! Стартовый код страницы входа в Shrine должен работать в вашем эмуляторе. Вы должны увидеть название "Shrine" и логотип Shrine чуть ниже него.

e7ed014e84755811.png

Давайте посмотрим на код. В нашем примере кода мы предоставили простую структуру навигации 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.

Теперь, когда вы ознакомились со стартовым кодом, давайте реализуем наш первый компонент.

3. Добавьте текстовые поля.

Для начала добавим на страницу входа два текстовых поля для ввода имени пользователя и пароля. Мы будем использовать компонент MDC Text Field, который включает в себя встроенную функцию отображения плавающей метки и сообщений об ошибках.

d83c47fb4aed3a82.png

Добавьте 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` для элемента TextInputLayout PasswordTextInputLayout` . Это добавит дополнительный отступ для сообщения об ошибке под текстовым полем.
  • Установите атрибут android:inputType со значением " textPassword " для элемента Password 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>

Теперь попробуйте запустить приложение. Вы должны увидеть страницу с двумя текстовыми полями: «Имя пользователя» и «Пароль»!

Оцените анимацию плавающей метки:

333184b615aed4f7.gif

4. Добавьте кнопки

Далее добавим на страницу входа две кнопки: «Отмена» и «Далее». Мы будем использовать компонент MDC Button, который поставляется со встроенным культовым эффектом «чернильной ряби» из Material Design.

4cb0c218948144b4.png

Добавьте 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>

Вот и всё! При запуске приложения при нажатии на каждую кнопку будет отображаться чернильная рябь.

9dd162d65e4a92a2.gif

5. Перейдите к следующему фрагменту.

Наконец, добавим немного 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() этот обработчик клика следует разместить между строкой вызова 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;
}            

Теперь мы можем перейти к другому фрагменту. Обновите 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.

6. Всё готово.

Используя базовую XML-разметку и около 30 строк кода на Java, библиотека Material Components for Android помогла вам создать красивую страницу входа в систему, соответствующую рекомендациям Material Design, а также обеспечивающую единообразный внешний вид и поведение на всех устройствах.

Следующие шаги

Текстовое поле и кнопка — два основных компонента библиотеки MDC для Android, но их гораздо больше! Вы можете изучить остальные компоненты в MDC Android . Также вы можете перейти к MDC 102: Структура и компоновка Material Design , чтобы узнать о верхней панели приложения, представлении карточек и сеточной компоновке. Спасибо за то, что попробовали Material Components. Надеемся, вам понравился этот практический урок!

Мне удалось выполнить это практическое задание за разумное время и с разумными затратами усилий.

Полностью согласен Соглашаться Нейтральный Не согласен Категорически не согласен

Я хотел бы и в будущем продолжать использовать компоненты Material.

Полностью согласен Соглашаться Нейтральный Не согласен Категорически не согласен