Создание красивых переходов с помощью Material Motion для Android

1. Введение

Material Design — это система для создания смелых и красивых цифровых продуктов. Объединив стиль, брендинг, взаимодействие и движение в рамках единого набора принципов и компонентов, продуктовые команды могут реализовать свой величайший дизайнерский потенциал.

logo_comComponents_color_2x_web_96dp.png

Material Components (MDC) помогают разработчикам реализовать Material Design. Созданный командой инженеров и UX-дизайнеров Google, MDC включает в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступен для Android, iOS, Интернета и Flutter.material.io/develop.

Что такое система движения Material для Android?

Система движения Material для Android — это набор шаблонов перехода в библиотеке MDC-Android, которые могут помочь пользователям понимать приложение и перемещаться по нему, как описано в рекомендациях Material Design .

Четыре основных шаблона перехода материалов следующие:

  • Преобразование контейнера: переходы между элементами пользовательского интерфейса, включающими контейнер; создает видимую связь между двумя отдельными элементами пользовательского интерфейса, плавно преобразуя один элемент в другой.
  • Общая ось: переходы между элементами пользовательского интерфейса, имеющими пространственные или навигационные отношения; использует общее преобразование по осям x, y или z, чтобы усилить связь между элементами.
  • Fade Through: переходы между элементами пользовательского интерфейса, которые не имеют сильной связи друг с другом; использует последовательное затухание и появление в масштабе входящего элемента.
  • Fade: используется для элементов пользовательского интерфейса, которые входят или выходят за пределы экрана.

Библиотека MDC-Android предлагает классы перехода для этих шаблонов, созданные на основе библиотеки AndroidX Transition ( androidx.transition ) и Android Transition Framework ( android.transition ):

AndroidX

  • Доступно в пакете com.google.android.material.transition .
  • Поддерживает уровень API 14+
  • Поддерживает фрагменты и представления, но не действия или Windows.
  • Содержит перенесенные исправления ошибок и единообразное поведение на всех уровнях API.

Рамки

  • Доступно в пакете com.google.android.material.transition.platform .
  • Поддерживает уровень API 21+
  • Поддерживает фрагменты, представления, действия и окна.
  • Исправления ошибок не перенесены и могут иметь различное поведение на разных уровнях API.

В этой лаборатории кода вы будете использовать переходы материалов, созданные на основе библиотеки AndroidX, то есть вы будете в основном сосредоточены на фрагментах и ​​представлениях.

Что ты построишь

Эта лаборатория кода поможет вам создать некоторые переходы в примере почтового приложения Android под названием Reply с использованием Kotlin и продемонстрировать, как можно использовать переходы из библиотеки MDC-Android для настройки внешнего вида вашего приложения.

Будет предоставлен стартовый код для приложения «Ответ», и вы добавите в приложение следующие переходы материалов, которые можно увидеть в GIF-файле завершенной кодовой лаборатории ниже:

  • Переход Container Transform со списка адресов электронной почты на страницу сведений об электронной почте
  • Переход Container Transform от FAB к странице создания электронной почты
  • Общий переход по оси Z от значка поиска на страницу просмотра поиска
  • Переход между страницами почтового ящика Fade Through
  • Переход Container Transform от чипа адреса электронной почты к представлению карты

The domain of the requested iframe (youtu.be) has not been whitelisted.

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

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

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

Новичок Средний Опытный

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

Запустите Android Studio

Когда вы открываете Android Studio , должно появиться окно под названием «Добро пожаловать в Android Studio». Однако если вы запускаете Android Studio впервые, выполните шаги мастера установки Android Studio со значениями по умолчанию . Этот шаг может занять несколько минут для загрузки и установки необходимых файлов, поэтому не стесняйтесь оставить этот процесс в фоновом режиме, пока вы выполняете следующий раздел.

Вариант 1. Клонируйте начальное приложение Codelab из GitHub.

Чтобы клонировать эту кодовую лабораторию из GitHub, выполните следующие команды:

git clone https://github.com/material-components/material-components-android-motion-codelab.git
cd material-components-android-motion-codelab

Вариант 2. Загрузите ZIP-файл начального приложения Codelab.

Стартовое приложение находится в каталоге material-components-android-motion-codelab-develop .

Загрузите стартовый код в Android Studio.

  1. После завершения работы мастера установки и появления окна «Добро пожаловать в Android Studio» нажмите « Открыть существующий проект Android Studio» .

e3f200327a67a53.png

  1. Перейдите в каталог, в который вы установили пример кода, и выберите каталог примера, чтобы открыть проект.
  2. Подождите, пока Android Studio создаст и синхронизирует проект, как показывают индикаторы активности в нижней части окна Android Studio.
  1. На этом этапе Android Studio может вызвать некоторые ошибки сборки, поскольку вам не хватает Android SDK или инструментов сборки, таких как показанный ниже. Следуйте инструкциям в Android Studio, чтобы установить/обновить их и синхронизировать проект. Если проблемы по-прежнему возникают, следуйте руководству по обновлению инструментов с помощью SDK Manager.

6e026ae171f5b1eb.png

Проверка зависимостей проекта

Проекту нужна зависимость от библиотеки MDC-Android . В загруженном вами примере кода эта зависимость уже должна быть указана, но давайте посмотрим на конфигурацию, чтобы убедиться в этом.

Перейдите к файлу build.gradle модуля app и убедитесь, что блок dependencies включает зависимость от MDC-Android:

implementation 'com.google.android.material:material:1.2.0'

Запустите стартовое приложение

  1. Убедитесь, что конфигурация сборки слева от выбора устройства — app .
  2. Нажмите зеленую кнопку «Выполнить/Воспроизвести», чтобы создать и запустить приложение.

24218d0a6ae25803.png

  1. Если в окне «Выбор цели развертывания» у вас уже есть устройство Android в списке доступных устройств, перейдите к шагу 8 . В противном случае нажмите «Создать новое виртуальное устройство» .
  2. На экране «Выбор оборудования» выберите телефонное устройство, например Pixel 3 , и нажмите «Далее» .
  3. На экране «Образ системы» выберите последнюю версию Android , желательно самого высокого уровня API. Если он не установлен, щелкните появившуюся ссылку «Загрузить» и завершите загрузку.
  4. Нажмите Далее .
  5. На экране виртуального устройства Android (AVD) оставьте настройки без изменений и нажмите « Готово» .
  6. Выберите устройство Android в диалоговом окне цели развертывания.
  7. Нажмите «ОК» .
  8. Android Studio создает приложение, развертывает его и автоматически открывает на целевом устройстве.

Успех! Стартовый код домашней страницы Reply должен быть запущен в вашем эмуляторе. Вы должны увидеть папку «Входящие», содержащую список писем.

cc73eb0d0f779035.png

Необязательно: замедлите анимацию устройства.

Поскольку эта кодовая лаборатория включает в себя быстрые, но отточенные переходы, может быть полезно замедлить анимацию устройства, чтобы наблюдать некоторые более мелкие детали переходов по мере их реализации. Это можно сделать с помощью команд оболочки adb или плитки быстрых настроек . Обратите внимание, что эти методы замедления анимации устройства также повлияют на анимацию на устройстве за пределами приложения «Ответить».

Способ 1: команды оболочки ADB

Чтобы замедлить анимацию устройства в 10 раз, вы можете запустить следующие команды из командной строки:

adb shell settings put global window_animation_scale 10
adb shell settings put global transition_animation_scale 10
adb shell settings put global animator_duration_scale 10

Чтобы вернуть нормальную скорость анимации устройства, выполните следующие команды:

adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1

Способ 2: плитка быстрых настроек

Альтернативно, чтобы настроить плитку быстрых настроек, сначала включите настройки разработчика на своем устройстве, если вы не сделали этого ранее:

  1. Откройте приложение «Настройки» устройства.
  2. Прокрутите вниз и нажмите «Об эмулируемом устройстве».
  3. Прокрутите вниз и быстро нажмите «Номер сборки», пока не будут включены настройки разработчика.

Затем выполните следующие действия, все еще в приложении «Настройки» устройства, чтобы включить плитку быстрых настроек:

  1. Нажмите значок поиска или строку поиска в верхней части экрана.
  2. Введите «плитки» в поле поиска.
  3. Нажмите на строку «Плитки разработчика быстрых настроек».
  4. Нажмите переключатель «Масштаб анимации окна».

Наконец, на протяжении всей кодовой лаборатории опустите панель системных уведомлений в верхней части экрана и используйте c7e3f98200023f6a.png Значок для переключения между медленной и нормальной анимацией.

3. Ознакомьтесь с примером кода приложения.

Давайте посмотрим на код. Мы предоставили приложение, которое использует библиотеку компонентов Jetpack Navigation для навигации между несколькими различными фрагментами, все в рамках одного действия MainActivity :

  • HomeFragment: отображает список писем.
  • EmailFragment: отображает одно полное электронное письмо.
  • ComposeFragment: позволяет составить новое электронное письмо.
  • SearchFragment: отображает представление поиска.

Во-первых, чтобы понять, как настроен граф навигации приложения, откройте navigation_graph.xml в каталоге app -> src -> main -> res -> navigation :

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/navigation_graph"
   app:startDestination="@id/homeFragment">

   <fragment
       android:id="@+id/homeFragment"
       android:name="com.materialstudies.reply.ui.home.HomeFragment"
       android:label="HomeFragment">
       <argument...>
       <action
           android:id="@+id/action_homeFragment_to_emailFragment"
           app:destination="@id/emailFragment" />
   </fragment>
   <fragment
       android:id="@+id/emailFragment"
       android:name="com.materialstudies.reply.ui.email.EmailFragment"
       android:label="EmailFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/composeFragment"
       android:name="com.materialstudies.reply.ui.compose.ComposeFragment"
       android:label="ComposeFragment">
       <argument...>
   </fragment>
   <fragment
       android:id="@+id/searchFragment"
       android:name="com.materialstudies.reply.ui.search.SearchFragment"
       android:label="SearchFragment" />
   <action
       android:id="@+id/action_global_homeFragment"
       app:destination="@+id/homeFragment"
       app:launchSingleTop="true"
       app:popUpTo="@+id/navigation_graph"
       app:popUpToInclusive="true"/>
   <action
       android:id="@+id/action_global_composeFragment"
       app:destination="@+id/composeFragment" />
   <action
       android:id="@+id/action_global_searchFragment"
       app:destination="@+id/searchFragment" />
</navigation>

Обратите внимание, что все упомянутые выше фрагменты присутствуют: в качестве фрагмента запуска по умолчанию установлен HomeFragment через app:startDestination="@id/homeFragment" . Это XML-определение графа назначения фрагмента, а также действия информируют сгенерированный код навигации Kotlin, с которым вы столкнетесь при подключении переходов.

Activity_main.xml

Затем взгляните на макет activity_main.xml в каталоге app -> src -> main -> res -> layout . Вы увидите NavHostFragment , настроенный с помощью графа навигации сверху:

<fragment
   android:id="@+id/nav_host_fragment"
   android:name="androidx.navigation.fragment.NavHostFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:defaultNavHost="true"
   app:navGraph="@navigation/navigation_graph"/>

Этот NavHostFragment заполняет экран и обрабатывает все изменения навигации по полноэкранным фрагментам в приложении. BottomAppBar и его привязанный FloatingActionButton , также в activity_main.xml , располагаются поверх текущего фрагмента, отображаемого NavHostFragment , и поэтому будут отображаться или скрываться в зависимости от места назначения фрагмента в предоставленном примере кода приложения.

Кроме того, BottomNavDrawerFragment в activity_main.xml — это нижний ящик, содержащий меню для навигации между различными почтовыми ящиками электронной почты, которое условно отображается с помощью кнопки с логотипом BottomAppBar «Ответить».

MainActivity.kt

Наконец, чтобы увидеть пример используемого действия навигации, откройте MainActivity.kt в каталоге app -> src -> main -> java -> com.materialstudies.reply.ui . Найдите функцию navigateToSearch() , которая должна выглядеть следующим образом:

private fun navigateToSearch() {
   val directions = SearchFragmentDirections.actionGlobalSearchFragment()
   findNavController(R.id.nav_host_fragment).navigate(directions)
}

Здесь показано, как можно перейти на страницу просмотра поиска без какого-либо специального перехода. В ходе этой лабораторной работы вы погрузитесь в MainActivity и четыре основных фрагмента Reply, чтобы настроить переходы материалов, которые работают в тандеме с различными действиями навигации по всему приложению.

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

4. Добавьте переход Container Transform из списка адресов электронной почты на страницу сведений об электронной почте.

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

Прежде чем добавлять какой-либо код, попробуйте запустить приложение «Ответить» и нажать на электронное письмо. Он должен выполнить простой переход, что означает, что экран заменяется без перехода:

f0e8a92eb2216bce.gif

Начните с добавления transitionName в MaterialCardView в email_item_layout.xml , как показано в следующем фрагменте:

электронная почта_item_layout.xml

android:transitionName="@{@string/email_card_transition_name(email.id)}"

Имя перехода принимает строковый ресурс с параметром. Вам необходимо использовать идентификатор каждого электронного письма, чтобы гарантировать уникальность каждого transitionName в нашем EmailFragment .

Теперь, когда у вас установлено имя перехода для элемента списка адресов электронной почты, давайте сделаем то же самое в макете сведений об электронной почте. В fragment_email.xml установите для transitionName MaterialCardView следующий строковый ресурс:

фрагмент_email.xml

android:transitionName="@string/email_card_detail_transition_name"

В HomeFragment.kt замените код в onEmailClicked приведенным ниже фрагментом, чтобы создать сопоставление из начального представления (элемент списка адресов электронной почты) и конечного представления (экран сведений об электронной почте):

ГлавнаяFragment.kt

val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name)
val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName)
val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id)
findNavController().navigate(directions, extras)

Теперь, когда у вас настроена сантехника, вы можете создать преобразование контейнера. В методе EmailFragment onCreate задайте sharedElementEnterTransition новый экземпляр MaterialContainerTransform (импортируя версию com.google.android.material.transition , а не версию com.google.android.material.transition.platform ), добавив следующий фрагмент :

EmailFragment.kt

sharedElementEnterTransition = MaterialContainerTransform().apply {
   drawingViewId = R.id.nav_host_fragment
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
}

Теперь попробуйте перезапустить приложение.

ed62cedec31da268.gif

Дела начинают выглядеть великолепно! Когда вы нажимаете на электронное письмо в списке адресов электронной почты, преобразование контейнера должно развернуть элемент списка на полноэкранную страницу сведений. Однако обратите внимание, что нажатие кнопки «Назад» не сворачивает письмо обратно в список. Кроме того, список адресов электронной почты исчезает сразу в начале перехода, показывая серый фон окна. Итак, мы еще не закончили.

Чтобы исправить обратный переход, добавьте следующие две строки в метод onViewCreated в HomeFragment.kt :

ГлавнаяFragment.kt

postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

Попробуйте перезапустить приложение. Нажатие кнопки «Назад» после открытия электронного письма приведет к свертыванию электронного письма обратно в список. Хороший! Давайте продолжим улучшать анимацию.

Проблема исчезновения списка адресов электронной почты связана с тем, что при переходе к новому фрагменту с помощью компонента навигации текущий фрагмент немедленно удаляется и заменяется нашим новым входящим фрагментом. Чтобы список адресов электронной почты оставался видимым даже после замены, вы можете добавить выходной переход в HomeFragment .

Добавьте приведенный ниже фрагмент в метод HomeFragment onEmailClicked , чтобы список электронных писем плавно масштабировался при выходе и возвращался при повторном входе:

ГлавнаяFragment.kt

exitTransition = MaterialElevationScale(false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Далее, чтобы гарантировать, что переход MaterialElevationScale применяется к главному экрану в целом, а не к каждому отдельному представлению в иерархии, отметьте RecyclerView в fragment_home.xml как группу перехода.

фрагмент_home.xml

android:transitionGroup="true"

На этом этапе у вас должна быть полностью работающая трансформация контейнера. При нажатии на электронное письмо элемент списка разворачивается на экран сведений, а список электронных писем удаляется. Нажатие «Назад» сворачивает экран сведений об электронной почте обратно в элемент списка, одновременно увеличивая список электронных писем.

9df2b39d5a150418.gif

5. Добавьте переход Container Transform из FAB на страницу создания электронной почты.

Давайте продолжим преобразование контейнера и добавим переход от плавающей кнопки действия к ComposeFragment , расширяя FAB до нового электронного письма, которое будет написано пользователем. Сначала перезапустите приложение и нажмите FAB, чтобы увидеть, что при запуске экрана создания электронной почты нет перехода.

d242c9708abd382c.gif

Хотя мы используем один и тот же класс перехода, способ настройки этого экземпляра будет другим, поскольку наш FAB находится в MainActivity , а наш ComposeFragment размещается внутри нашего хост-контейнера навигации MainActivity .

В ComposeFragment.kt добавьте следующий фрагмент в метод onViewCreated , обязательно импортировав версию Slide androidx.transition .

ComposeFragment.kt

enterTransition = MaterialContainerTransform().apply {
   startView = requireActivity().findViewById(R.id.fab)
   endView = emailCardView
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   scrimColor = Color.TRANSPARENT
   containerColor = requireContext().themeColor(R.attr.colorSurface)
   startContainerColor = requireContext().themeColor(R.attr.colorSecondary)
   endContainerColor = requireContext().themeColor(R.attr.colorSurface)
}
returnTransition = Slide().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_medium).toLong()
   addTarget(R.id.email_card_view)
}

В дополнение к параметрам, которые использовались для настройки нашего предыдущего преобразования контейнера, здесь вручную задаются startView и endView . Вместо использования transitionName , чтобы сообщить системе Android Transition, какие представления следует преобразовать, при необходимости вы можете указать их вручную.

Теперь перезапустите приложение. Вы должны увидеть, как FAB превращается в экран создания сообщения (см. GIF в конце этого шага).

Как и в предыдущем шаге, вам необходимо добавить переход к HomeFragment , чтобы он не исчез после удаления и замены ComposeFragment .

Скопируйте приведенный ниже фрагмент в метод navigateToCompose в MainActivity перед вызовом NavController navigate .

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialElevationScale(false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialElevationScale(true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Вот и все на этом этапе! У вас должен получиться переход от FAB к экрану создания сообщения, который выглядит следующим образом:

81b68391ac4b0a9.gif

6. Добавьте переход по общей оси Z от значка поиска на страницу просмотра поиска.

На этом этапе мы добавим переход от значка поиска к полноэкранному режиму поиска. Поскольку в этом изменении навигации не задействован постоянный контейнер, мы можем использовать переход «Общая ось Z», чтобы усилить пространственные отношения между двумя экранами и указать перемещение на один уровень вверх в иерархии приложения.

Прежде чем добавлять какой-либо дополнительный код, попробуйте запустить приложение и нажать значок поиска в правом нижнем углу экрана. Должен появиться экран просмотра поиска без перехода.

499e1a677b4216bb.gif

Для начала найдите метод navigateToSearch в MainActivity и добавьте следующий фрагмент кода перед вызовом метода navigate NavController , чтобы настроить выход текущего фрагмента и повторный ввод переходов Z-Axis MaterialSharedAxis .

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
   reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Затем добавьте следующий фрагмент кода в метод onCreate в SearchFragment , который настраивает переходы ввода и возврата MaterialSharedAxis .

ПоискФрагмент.kt

enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Наконец, чтобы гарантировать, что переход MaterialSharedAxis применяется к экрану поиска в целом, а не к каждому отдельному представлению в иерархии, отметьте LinearLayout в fragment_search.xml как группу переходов.

фрагмент_search.xml

android:transitionGroup="true"

Вот и все! Теперь попробуйте перезапустить приложение и нажать на значок поиска. Главный экран и экран просмотра поиска должны одновременно исчезать и масштабироваться по оси Z, создавая плавный эффект между двумя экранами.

e5c0b0a130e807db.gif

7. Добавьте переход Fade Through между страницами почтового ящика.

На этом этапе мы добавим переход между разными почтовыми ящиками. Поскольку мы не хотим подчеркивать пространственные или иерархические отношения, мы воспользуемся плавным переходом, чтобы выполнить простой «обмен» между списками электронных писем.

Прежде чем добавлять какой-либо дополнительный код, попробуйте запустить приложение, коснувшись логотипа «Ответить» в нижней панели приложения и переключив почтовые ящики. Список адресов электронной почты должен меняться без перехода.

2c874c0a4588e8fb.gif

Для начала найдите метод navigateToHome в MainActivity и добавьте следующий фрагмент кода перед вызовом метода navigate NavController , чтобы настроить переход MaterialFadeThrough выхода текущего фрагмента.

MainActivity.kt

currentNavigationFragment?.apply {
   exitTransition = MaterialFadeThrough().apply {
       duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
   }
}

Затем откройте HomeFragment . В onCreate установите для enterTransition фрагмента новый экземпляр MaterialFadeThrough .

ГлавнаяFragment.kt

enterTransition = MaterialFadeThrough().apply {
   duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}

Перезапустите приложение. Когда вы открываете нижнюю панель навигации и меняете почтовые ящики, текущий список электронных писем должен исчезать и уменьшаться, в то время как новый список исчезает и увеличивается. Отлично!

f61dfd58ea7bd3fd.gif

8. Добавьте переход Container Transform от чипа адреса электронной почты к виду карты.

На этом этапе вы добавите переход, который преобразует чип во всплывающую карточку. Здесь используется преобразование контейнера, чтобы сообщить пользователю, что действие, предпринятое во всплывающем окне, повлияет на чип, из которого возникло всплывающее окно.

Прежде чем добавлять какой-либо код, запустите приложение «Ответить», щелкните электронное письмо, нажмите кнопку «Ответить» FAB, а затем попробуйте нажать на контактный чип получателя. Чип должен мгновенно исчезнуть, и карточка с адресами электронной почты этого контакта должна появиться без анимации.

6200c682da2382d5.gif

На этом этапе вы будете работать в ComposeFragment . В макет ComposeFragment уже добавлены чипы получателя (видимые по умолчанию) и карта получателя (невидимая по умолчанию). Чип получателя и эта карточка — это два представления, между которыми вы создадите преобразование контейнера.

Для начала откройте ComposeFragment и найдите expandChip . Этот метод вызывается при щелчке по предоставленному chip . Добавьте следующий фрагмент кода над строками, которые меняют местами recipientCardView и видимость chip , что запустит преобразование контейнера, зарегистрированное через beginDelayedTransition .

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = chip
   endView = binding.recipientCardView
   scrimColor = Color.TRANSPARENT
   endElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(binding.recipientCardView)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

Если вы запустите приложение сейчас, чип должен превратиться в карту адресов электронной почты получателя. Далее настроим обратный переход, чтобы свернуть карту обратно в чип.

В collapseChip в ComposeFragment добавьте приведенный ниже фрагмент кода, чтобы свернуть карту обратно в чип.

ComposeFragment.kt

val transform = MaterialContainerTransform().apply {
   startView = binding.recipientCardView
   endView = chip
   scrimColor = Color.TRANSPARENT
   startElevation = requireContext().resources.getDimension(
       R.dimen.email_recipient_card_popup_elevation_compat
   )
   addTarget(chip)
}

TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)

Перезапустите приложение. Щелчок по чипу должен превратить его в карту, а щелчок по карте свернет карту обратно в чип. Хороший!

e823b28e2890e05d.gif

9. Все готово

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

454a47ba96017a25.gif

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

Для получения дополнительной информации о системе движения Material обязательно ознакомьтесь со спецификацией и полной документацией для разработчиков и попробуйте добавить несколько переходов Material в свое приложение!

Спасибо за попытку Material motion. Мы надеемся, что вам понравилась эта кодовая лаборатория!

Мне удалось завершить эту кодовую работу, потратив разумное количество времени и усилий.

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

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

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