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

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/kotlin .

...или клонируйте его с 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» . Перейдите в каталог, где вы установили примеры кода, и выберите kotlin -> shrine (или найдите shrine на своем компьютере), чтобы открыть проект Shipping.
  2. Подождите немного, пока Android Studio соберет и синхронизирует проект, как это отобразится в индикаторах активности в нижней части окна Android Studio.
  3. На этом этапе Android Studio может выдавать ошибки сборки, поскольку у вас отсутствует Android SDK или инструменты сборки, например, показанные ниже. Следуйте инструкциям в Android Studio, чтобы установить/обновить их и синхронизировать ваш проект.

KzoYWC1S7Se7yL8igi1vXF_mbVxAdl2lg5kb7RODrsVpEng0G6U3NK1Qnn0faBBZd2u71yMXioy9tD-7fv3NXvVO4N3EtMMeWDTmqBMMl6egd9R5uXX0T_SKmahbmRor3wZZHX0ByA

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

Проекту необходима зависимость от библиотеки поддержки 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.kt в директории shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.kotlin.shrine . Он должен содержать следующее:

MainActivity.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment

class MainActivity : AppCompatActivity(), NavigationHost {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.shr_main_activity)

       if (savedInstanceState == null) {
           supportFragmentManager
                   .beginTransaction()
                   .add(R.id.container, LoginFragment())
                   .commit()
       }
   }

   override fun navigateTo(fragment: Fragment, addToBackstack: Boolean) {
       val transaction = supportFragmentManager
               .beginTransaction()
               .replace(R.id.container, fragment)

       if (addToBackstack) {
           transaction.addToBackStack(null)
       }

       transaction.commit()
   }
}

Эта активность отображает файл макета R.layout.shr_main_activity , определенный в shr_main_activity.xml .

Как видите, в onCreate(), MainActivity.kt запускает транзакцию 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.kt .

LoginFragment.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class LoginFragment : Fragment() {

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment
       val view = inflater.inflate(R.layout.shr_login_fragment, container, false)

       return view
   }
}

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" />
   </LinearLayout>
</ScrollView>

Здесь мы видим элемент <LinearLayout> с элементом <ImageView> вверху, представляющим логотип храма.

Далее следует тег <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" />
</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" />
</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. Перейдите к следующему фрагменту.

Наконец, добавим немного кода на Kotlin в LoginFragment.kt , чтобы связать нашу кнопку "ДАЛЕЕ" с переходом к другому фрагменту.

Добавим в LoginFragment.kt приватный логический метод isPasswordValid под onCreateView() , содержащий логику для определения того, действителен ли пароль. Для целей этой демонстрации мы просто убедимся, что пароль состоит как минимум из 8 символов:

LoginFragment.kt

private fun isPasswordValid(text: Editable?): Boolean {
   return text != null && text.length >= 8
}

Далее добавьте обработчик клика к кнопке "Далее", который будет устанавливать и сбрасывать ошибку в зависимости от метода isPasswordValid() который мы только что создали. В onCreateView() этот обработчик клика следует разместить между строкой вызова inflater и строкой return view .

Теперь добавим обработчик событий нажатия клавиш к полю ввода пароля TextInputEditText , чтобы отслеживать события нажатия клавиш, которые устранят ошибку. Этот обработчик также должен использовать isPasswordValid() для проверки корректности пароля. Вы можете добавить его непосредственно под обработчиком кликов в onCreateView() .

Теперь ваш метод onCreateView() должен выглядеть примерно так:

LoginFragment.kt

override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment.
       val view = inflater.inflate(R.layout.shr_login_fragment, container, false)

       // Set an error if the password is less than 8 characters.
       view.next_button.setOnClickListener({
           if (!isPasswordValid(password_edit_text.text!!)) {
               password_text_input.error = getString(R.string.shr_error_password)
           } else {
               // Clear the error.
               password_text_input.error = null
           }
       })

       // Clear the error once more than 8 characters are typed.
       view.password_edit_text.setOnKeyListener({ _, _, _ ->
           if (isPasswordValid(password_edit_text.text!!)) {
               // Clear the error.
               password_text_input.error = null
           }
           false
       })

       return view
   }
}

Теперь мы можем перейти к другому фрагменту. В onCreateView() обновите OnClickListener , чтобы при успешной проверке ошибок происходил переход к другому фрагменту. Ваш код clickListener теперь должен выглядеть следующим образом:

LoginFragment.kt

// Set an error if the password is less than 8 characters.
view.next_button.setOnClickListener({
   if (!isPasswordValid(password_edit_text.text!!)) {
       password_text_input.error = getString(R.string.shr_error_password)
   } else {
       // Clear the error.
       password_text_input.error = null
       // Navigate to the next Fragment.
       (activity as NavigationHost).navigateTo(ProductGridFragment(), false)
   }
})

Мы добавили строку ( activity as NavigationHost).navigateTo(ProductGridFragment(), false ) в блок else обработчика клика. Эта строка вызывает метод navigateTo() из MainActivity для перехода к новому фрагменту — ProductGridFragment . В настоящее время это пустая страница, с которой вы будете работать в курсе MDC-102.

Теперь соберите приложение. Нажмите кнопку «Далее».

Вы справились! Этот экран станет отправной точкой для нашей следующей практической работы, которую вы будете выполнять в рамках курса MDC-102.

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

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

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

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

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

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

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

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