← Back to list

Material Design Motion — заметки на полях

История анимации в андроид долга и запутана. Здесь я собрал, описание переходов между фрагментами и видами…

Виталий Шеянов · 2020-09-13 20:29 · 6 claps · 4.6 min read
#androiddev #material-design
Open on Medium ↗

Material Design Motion — заметки на полях

Photo by Clark Van Der Beken on Unsplash

Photo by Clark Van Der Beken on Unsplash

История анимации в андроид долга и запутана. Здесь я собрал (в первую очередь для себя самого), описание переходов между фрагментами и видами начиная с material:1.2.0

В данной версии библиотека стала включать в себя набор стандартных шаблонов для помощи в реализации переходов и анимации.

дисклеймер — всё аниму нагло сперто с material.io

Шаблоны перехода:

  • Persistent container: используется в переходах включающих в себя преобразование постоянного элемента (кнопки в список, списка в карточку и т.д.)
  • Shared axis: общая ось используется для переходов между элементами имеющими пространственные или навигационные зависимости.
  • Fade through: Исчезновение применяется когда связь между элементами несущественна.
  • Fade: Применяется в элементах интерфейса выходящих за пределы экрана

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

  • В xml макетах в корневом layout используйте android:transitionGroup=”true”
  • Для контейнера фрагментов используйте androidx.fragment.app.FragmentContainerView, если после этого ваша программа стала вываливаться с ошибкой: Nav Controller не найден, поздравляю, вы скорее всего используете findNavController(idContainer) в activity, ошибка известная и конечно вечная, вместо этого используйте *(supportFragmentManager*.findFragmentById(idContainer) as NavHostFragment).navController .
  • Не забывайте класс Hold для удержания “уходящего” фрагмента, не забывайте что у этого класса нужно тоже настроить продолжительность “анимации” иначе он может уйти слишком быстро или задержаться дольше чем нужно.
  • Изображения использующие Fresco и т.п. библиотеки могут по умолчанию не работать как надо, например: используя Frsesco изображение в уходящем фрагменте будет исчезать сразу в начале перехода, так как библиотека будет считать что оно уже не нужно. О том какой костыль использовал я в конце статьи.
  • По возможности используйте классы из com.google.android.material.transition, а не com.google.android.material.transition.platform т.е. иными словами делайте приложение с одной activity ну или почти одной
  • При некрасивом по цвету поведении (например прозрачном фоне в процессе анимации), не спешите указывать blackground в корне макета фрагментов, сначала проверьте правильность настройки цветов в самой анимации.
  • Не стесняйтесь использовать isDrawDebugEnabled=true в классах трансформации.

Продолжаем разговор…

Практически во всех классах анимации есть duration и interpolator, гайдлайн от гугла находится здесь. Спойлер для прямой и обратной анимации рекомендуется разное время, видимо чтоб жизнь не казалась слишком легкой.

Persistent container

Используется для создания видимой связи между двумя элементами, превращая один элемент в другой. Например Fab в другой фрагмент или меню.

Класс MaterialContainerTransform

ключевые методы

  • containerColor

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

  • scrimColor

Задает цвет которой будет отображаться под контейнером самого процессе трансформации. Сам же контейнер можно задать с помощью setDrawingViewId()

  • fadeMode

Режим затухания при переключении из начального в конечное представление.

FADE_MODE_IN: Режим по умолчанию, уходящий элемент не затухает до самого конца анимации (это хорошо видно если фон входящего контента прозрачный, например у вас Fab яркого цвета переходит в фрагмент с тёмным фоном, до самого конца анимации в фоне у вас будет видна кнопка с ярким цветом), приходящий элемент становится все более непрозрачным.

FADE_MODE_OUT: Прямо противоположное IN

FADE_MODE_CROSS: Плавный переход от одного элемента к другому

FADE_MODE_THROUGH: Отличие от CROSS в том что в процессе анимации у вас будет момент когда один элемент уже не отображается, а второй ещё не отображается.

  • fitMode

Подгонка входящего содержимого по высоте или ширине к исходящему в процессе анимации. Соответственно есть три варианта: FIT_MODE_HEIGHT, FIT_MODE_WIDTH, FIT_MODE_AUTO

Shared axis

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

Класс MaterialSharedAxis(axis, forward)

оси X, Y обычно используются для перемещения по шагам (заказе, руководстве) или одинаковыми в иерархии экранами в приложении.

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

Вообще в этом классе происходит сразу две трансформации, скольжение по XY или масштабирование в случае Z, и затухание, соответственно отключить/настроить можно каждую из них, например затухание отключается через secondaryAnimatorProvider = null

Fade Through

Исчезновение используется для переходов не имеющих прочной связи друг с другом

Класс MaterialFadeThrough

Соответственно так же имеет две анимации исчезновение и масштабирование.

Хороший выбор для нижней панели навигации.

Fade

Класс MaterialFade

Почти тоже что и предыдущее, но не так глобально. Класс так же содержит две анимации.

О фрагментах и навигации

Если верить руководству, то для анимации почти ничего не нужно делать. Всё что надо, определить уникальное имя для двух view элементов android:transitionName=”shared_element_container” и в случае навигации использовать:

val extras = FragmentNavigatorExtras(view to "shared_element_container")
findNavController().navigate(R.id.action_fragmentA_to_fragmentB, null, null, extras)

И в входящем фрагменте использовать что-то вроде

override fun onCreate(savedInstanceState: Bundle?)  {
  super.onCreate(savedInstanceState)
  sharedElementEnterTransition = MaterialContainerTransform()
}

Но есть нюансы.

Если вы используете ViewBinding, то в onCreate вы не можете использовать FragmentBinding.myView, из onCreate плавно перемещаемся в onCreateView.

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

exitTransition = Hold().apply {
    duration = 300L
}

Да нужно не забыть установить время удержания.

Так же иногда может пригодится класс TransitionSet для совмещения нескольких анимаций

Всякое разное

Отложенная анимация

Может так случиться, что нужно отложить анимацию например до поступления данных, для этого есть пара замечательных методов.

Сначала в onCreate или onAttach или onCreateView фрагмента вы вызываете метод postponeEnterTransition()

затем при поступлении данных startPostponedEnterTransition()

Fresco

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

Откуда получаю Bitmap? Хороший вопрос, в моем конкретном случае я использую свой PostProcessor, в котором держу как раз для этого случая скопированный bitmap и беру его.

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

Немного ссылок

[embed]Material Design Build beautiful, usable products faster. Material Design is an adaptable system-backed by open-source code-that helps…material.io

[embed]Understanding Motion Build beautiful, usable products faster. Material Design is an adaptable system-backed by open-source code-that helps…material.io


메타데이터
post_id
a3de04492d89
slug
material-design-motion-a3de04492d89
url
https://medium.com/@vit.onix/material-design-motion-a3de04492d89
canonical_url
https://medium.com/@vit.onix/material-design-motion-a3de04492d89
author_url
https://medium.com/@vit.onix
status
ok
fetched_at
2026-07-28 20:20:15