1. Введение
Material Design — это система для создания смелых и красивых цифровых продуктов. Объединяя стиль, брендинг, взаимодействие и анимацию в рамках единого набора принципов и компонентов, продуктовые команды могут реализовать свой максимальный дизайнерский потенциал.
Компоненты Material (MDC) помогают разработчикам внедрять Material Design. Созданные командой инженеров и UX-дизайнеров Google, MDC включают в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступны для Android, iOS, веб-приложений и Flutter.material.io/develop |
Что представляет собой система анимации Material Design для Android?
Система анимации Material Design для Android представляет собой набор шаблонов переходов в библиотеке MDC-Android, которые помогают пользователям понимать и перемещаться по приложению, как описано в рекомендациях Material Design .
Четыре основных типа материальных переходов следующие:
- Трансформация контейнера: переход между элементами пользовательского интерфейса, содержащими контейнер; создает видимую связь между двумя различными элементами пользовательского интерфейса путем плавного преобразования одного элемента в другой.
- Общая ось: переходы между элементами пользовательского интерфейса, имеющими пространственную или навигационную связь; использует общее преобразование по осям x, y или z для усиления связи между элементами.
- Плавный переход: используется для перехода между элементами пользовательского интерфейса, не имеющими тесной взаимосвязи; применяется последовательное затухание и появление с масштабированием, зависящим от входящего элемента.
- Затухание: используется для элементов пользовательского интерфейса, которые появляются или исчезают в пределах границ экрана.
Библиотека MDC-Android предлагает классы переходов для этих шаблонов, построенные на основе как библиотеки переходов AndroidX ( androidx.transition ), так и фреймворка переходов Android ( android.transition ):
AndroidX
- Доступно в пакете
com.google.android.material.transition - Поддерживает API уровня 14+
- Поддерживает фрагменты и представления, но не действия или окна.
- Содержит исправления ошибок, перенесенные из предыдущих версий, и обеспечивает единообразное поведение на всех уровнях API.
Рамки
- Доступно в пакете
com.google.android.material.transition.platform - Поддерживает API уровня 21+
- Поддерживает фрагменты, представления, действия и окна.
- Исправления ошибок не были перенесены в более ранние версии и могут иметь различное поведение на разных уровнях API.
В этом практическом занятии вы будете использовать переходы Material Design, созданные на основе библиотеки AndroidX, то есть основное внимание будет уделено фрагментам и представлениям.
Что вы построите
В этом практическом занятии мы покажем вам, как создать несколько переходов в примере почтового приложения Android под названием Reply , используя Kotlin, чтобы продемонстрировать, как можно использовать переходы из библиотеки MDC-Android для настройки внешнего вида вашего приложения.
Вам будет предоставлен исходный код для приложения Reply, и вы должны будете интегрировать в приложение следующие переходы Material Design, которые можно увидеть на GIF-анимации из готового примера ниже:
- Переход с помощью функции Container Transform со списка рассылок на страницу с подробной информацией о рассылке.
- Переход от кнопки FAB к странице создания электронного письма с помощью функции Container Transform
- Общий переход по оси Z от значка поиска к странице результатов поиска.
- Плавный переход между страницами почтового ящика
- Переход в режиме контейнерного преобразования от отображения адреса электронной почты в виде карточки

Что вам понадобится
- Базовые знания разработки под 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.
- После завершения работы мастера установки и появления окна «Добро пожаловать в Android Studio» нажмите « Открыть существующий проект Android Studio» .

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

Проверьте зависимости проекта.
Проекту необходима зависимость от библиотеки MDC-Android . В загруженном вами примере кода эта зависимость уже должна быть указана, но давайте проверим конфигурацию, чтобы убедиться в этом.
Перейдите к файлу build.gradle модуля app и убедитесь, что блок dependencies включает зависимость от MDC-Android:
implementation 'com.google.android.material:material:1.2.0'
Запустите стартовое приложение
- Убедитесь, что в конфигурации сборки слева от выбора устройства указано
app. - Нажмите зеленую кнопку «Запустить/Играть» , чтобы собрать и запустить приложение.

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

Дополнительно: Замедлить анимацию на устройстве
Поскольку в этом практическом задании используются быстрые, но отточенные переходы, может быть полезно замедлить анимацию устройства, чтобы рассмотреть некоторые более тонкие детали переходов в процессе реализации. Это можно сделать либо с помощью команд adb shell, либо с помощью плитки быстрых настроек . Обратите внимание, что эти методы замедления анимации устройства повлияют и на анимацию на устройстве вне приложения «Ответить».
Метод 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: Плитка быстрых настроек
В качестве альтернативы, чтобы настроить плитку быстрых настроек, сначала включите режим разработчика на своем устройстве, если вы еще этого не сделали:
- Откройте приложение «Настройки» на устройстве.
- Прокрутите страницу вниз и нажмите «О программе эмулируемого устройства».
- Прокрутите страницу вниз и быстро нажимайте на кнопку «Номер сборки», пока не будут включены параметры разработчика.
Далее, оставаясь в приложении «Настройки» на устройстве, выполните следующие действия, чтобы включить плитку быстрых настроек:
- Нажмите на значок поиска или строку поиска в верхней части экрана.
- Введите "плитки" в поле поиска.
- Нажмите на строку "Плитки разработчика быстрых настроек".
- Нажмите переключатель "Масштаб анимации окна".
Наконец, на протяжении всего практического занятия опускайте панель системных уведомлений в верхней части экрана и используйте...
Значок для переключения между медленной и нормальной скоростью анимации.
3. Ознакомьтесь с примером кода приложения.
Давайте посмотрим на код. Мы предоставили приложение, которое использует библиотеку компонентов Jetpack Navigation для навигации между несколькими различными фрагментами, и все это в рамках одной Activity, MainActivity :
- HomeFragment: отображает список электронных писем
- EmailFragment: отображает одно полное электронное письмо.
- ComposeFragment: позволяет создавать новые электронные письма.
- SearchFragment: отображает окно поиска
navigation_graph.xml
Для начала, чтобы понять, как устроена навигационная сеть приложения, откройте файл 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 и четыре основных фрагмента, чтобы настроить переходы Material Design, которые будут работать в тандеме с различными действиями навигации по всему приложению.
Теперь, когда вы ознакомились со стартовым кодом, давайте реализуем наш первый переход.
4. Добавьте переход «Преобразование контейнера» из списка электронных писем на страницу с подробной информацией об электронном письме.
Для начала добавим эффект перехода при нажатии на электронное письмо. Для этого изменения навигации хорошо подходит шаблон преобразования контейнера, поскольку он предназначен для переходов между элементами пользовательского интерфейса, содержащими контейнер. Этот шаблон создает видимую связь между двумя элементами пользовательского интерфейса.
Прежде чем добавлять какой-либо код, попробуйте запустить приложение «Ответить» и нажать на электронное письмо. Должно произойти простое переключение, то есть экран будет заменен без перехода:

Для начала добавьте атрибут transitionName к элементу MaterialCardView в файле email_item_layout.xml , как показано в следующем фрагменте кода:
email_item_layout.xml
android:transitionName="@{@string/email_card_transition_name(email.id)}"
В качестве имени перехода используется строковый ресурс с параметром. Необходимо использовать идентификатор каждого электронного письма, чтобы гарантировать уникальность каждого transitionName в вашем EmailFragment .
Теперь, когда вы задали имя перехода для элемента списка писем, давайте сделаем то же самое для макета сведений о письме. В fragment_email.xml установите transitionName для MaterialCardView на следующий строковый ресурс:
фрагмент_электронной почты.xml
android:transitionName="@string/email_card_detail_transition_name"
В HomeFragment.kt замените код в обработчике onEmailClicked приведенным ниже фрагментом, чтобы создать сопоставление между начальным представлением (элемент списка писем) и конечным представлением (экран с подробными сведениями о письме):
HomeFragment.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)
Теперь, когда вы настроили инфраструктуру, вы можете создать контейнерное преобразование. В методе onCreate EmailFragment установите 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))
}
Теперь попробуйте запустить приложение снова.

Всё начинает выглядеть отлично! При нажатии на письмо в списке рассылки, функция преобразования контейнера должна развернуть элемент списка на всю страницу с подробной информацией. Однако обратите внимание, что нажатие кнопки «Назад» не сворачивает письмо обратно в список. Кроме того, список рассылок мгновенно исчезает в начале перехода, отображая серый фон окна. Так что это ещё не всё.
Чтобы исправить эффект возврата, добавьте следующие две строки в метод onViewCreated в HomeFragment.kt :
HomeFragment.kt
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
Попробуйте перезапустить приложение. Нажатие кнопки «Назад» после открытия письма свернёт его обратно в список. Отлично! Давайте продолжим улучшать анимацию.
Проблема исчезновения списка рассылки возникает из-за того, что при переходе к новому фрагменту с помощью компонента навигации текущий фрагмент немедленно удаляется и заменяется нашим новым, входящим фрагментом. Чтобы список рассылки оставался видимым даже после замены, вы можете добавить анимацию при выходе из HomeFragment .
Добавьте следующий фрагмент кода в метод onEmailClicked HomeFragment , чтобы список писем плавно уменьшался при выходе и снова увеличивался при повторном входе:
HomeFragment.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 как группу переходов.
фрагмент_дом.xml
android:transitionGroup="true"
На этом этапе у вас должна быть полностью работоспособная трансформация контейнера. Щелчок по электронному письму разворачивает элемент списка в экран с подробными сведениями, одновременно уменьшая список писем. Нажатие кнопки «Назад» сворачивает экран с подробными сведениями об электронном письме обратно в элемент списка, при этом увеличивая масштаб списка писем.

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

Хотя мы используем один и тот же класс перехода, способ настройки этого экземпляра будет отличаться, поскольку наш 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, какие представления должны быть преобразованы, вы можете указать их вручную при необходимости.
Теперь запустите приложение снова. Вы должны увидеть, как кнопка 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 к экрану создания сообщения, который будет выглядеть следующим образом:

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

Для начала найдите метод navigateToSearch в MainActivity и добавьте следующий фрагмент кода перед вызовом метода navigate NavController , чтобы настроить переходы по оси Z 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 при входе и выходе из него.
SearchFragment.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 как группу переходов.
fragment_search.xml
android:transitionGroup="true"
Вот и всё! Теперь попробуйте снова запустить приложение и нажать на значок поиска. Главный экран и экран поиска должны одновременно плавно переходить друг в друга по оси Z, создавая эффект бесшовного перехода между двумя экранами.

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

Для начала найдите метод 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 .
HomeFragment.kt
enterTransition = MaterialFadeThrough().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
Перезапустите приложение. Когда вы откроете нижнюю панель навигации и смените почтовый ящик, текущий список писем должен плавно исчезать и уменьшаться, а новый список — плавно появляться и уменьшаться. Отлично!

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

На этом этапе вы будете работать в 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)
Перезапустите приложение. При нажатии на чип он должен развернуться в карту, а при нажатии на карту — свернуть карту обратно в чип. Отлично!

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

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