MotionLayout — это тип макета, который помогает управлять анимацией движения и виджетов в вашем приложении. MotionLayout является подклассом ConstraintLayout и расширяет его богатые возможности в области компоновки. MotionLayout доступен в качестве вспомогательной библиотеки в составе библиотеки ConstraintLayout .
MotionLayout устраняет разрыв между переходами между элементами макета и сложной обработкой движения, предлагая сочетание функций, заимствованных из фреймворка анимации свойств , TransitionManager и CoordinatorLayout .
Помимо описания переходов между макетами, MotionLayout позволяет анимировать любые свойства макета. Более того, он изначально поддерживает переходы с возможностью перемещения курсора . Это означает, что вы можете мгновенно отобразить любую точку внутри перехода на основе какого-либо условия, например, ввода с помощью сенсорного экрана. MotionLayout также поддерживает ключевые кадры, что позволяет полностью настраивать переходы в соответствии с вашими потребностями.
MotionLayout — это полностью декларативный инструмент, то есть вы можете описать любые переходы в XML, независимо от их сложности.
Вопросы проектирования
MotionLayout предназначен для перемещения, изменения размера и анимации элементов пользовательского интерфейса, с которыми взаимодействуют пользователи, таких как кнопки и заголовки. Не используйте анимацию в своем приложении как ненужный спецэффект. Используйте ее, чтобы помочь пользователям понять, что делает ваше приложение. Для получения дополнительной информации о разработке приложений с использованием анимации см. раздел Material Design «Понимание анимации» .
Начать
Выполните следующие шаги, чтобы начать использовать MotionLayout в своем проекте.
Добавьте зависимость
ConstraintLayout: чтобы использоватьMotionLayoutв вашем проекте, добавьте зависимостьConstraintLayout2.0 в файлbuild.gradleвашего приложения. Если вы используете AndroidX, добавьте следующую зависимость:классный
dependencies { implementation "androidx.constraintlayout:constraintlayout:2.2.1" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1" }
Котлин
dependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.1") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1") }
Создайте файл
MotionLayout:MotionLayoutявляется подклассомConstraintLayout, поэтому вы можете преобразовать любой существующийConstraintLayoutвMotionLayout, заменив имя класса в файле ресурсов макета, как показано в следующих примерах:AndroidX
<!-- before: ConstraintLayout --> <androidx.constraintlayout.widget.ConstraintLayout .../> <!-- after: MotionLayout --> <androidx.constraintlayout.motion.widget.MotionLayout .../>
Библиотека поддержки
<!-- before: ConstraintLayout --> <android.support.constraint.ConstraintLayout .../> <!-- after: MotionLayout --> <android.support.constraint.motion.MotionLayout .../>
Вот полный пример файла
MotionLayout, определяющего макет, показанный на рисунке 1:AndroidX
<?xml version="1.0" encoding="utf-8"?> <!-- activity_main.xml --> <androidx.constraintlayout.motion.widget.MotionLayout 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:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/scene_01" tools:showPaths="true"> <View android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:background="@color/colorAccent" android:text="Button" /> </androidx.constraintlayout.motion.widget.MotionLayout>
Библиотека поддержки
<?xml version="1.0" encoding="utf-8"?> <!-- activity_main.xml --> <android.support.constraint.motion.MotionLayout 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:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/scene_01" tools:showPaths="true"> <View android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:background="@color/colorAccent" android:text="Button" /> </android.support.constraint.motion.MotionLayout>
Создание MotionScene: в предыдущем примере
MotionLayoutатрибутapp:layoutDescriptionссылается на MotionScene . MotionScene — это XML-файл ресурсов. Внутри своего корневого элемента<MotionScene>MotionScene содержит все описания движений для соответствующего макета. Чтобы информация о макете была отделена от описаний движений, каждыйMotionLayoutссылается на отдельную MotionScene. Определения в MotionScene имеют приоритет над любыми аналогичными определениями вMotionLayout.Вот пример файла с описанием движения, демонстрирующего базовое горизонтальное движение на рисунке 1:
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> <OnSwipe motion:touchAnchorId="@+id/button" motion:touchAnchorSide="right" motion:dragDirection="dragRight" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> </MotionScene>
Обратите внимание на следующее:
<Transition>содержит базовое определение движения.motion:constraintSetStartиmotion:constraintSetEnd— это ссылки на конечные точки движения. Эти конечные точки определяются в элементах<ConstraintSet>далее в сцене движения.motion:durationуказывает количество миллисекунд, необходимое для завершения движения.
Функция
<OnSwipe>позволяет настроить сенсорное управление движением.motion:touchAnchorIdобозначает область, которую пользователь может пролистывать и перетаскивать.motion:touchAnchorSideозначает, что элемент управления перетаскивается с правой стороны.motion:dragDirectionзадает направление перетаскивания . Например,motion:dragDirection="dragRight"означает, что продвижение увеличивается по мере перетаскивания элемента вправо.
В разделе
<ConstraintSet>вы определяете различные ограничения, описывающие ваше движение. В этом примере для каждой конечной точки вашего движения определен отдельный раздел<ConstraintSet>. Эти конечные точки центрируются по вертикали с помощьюapp:layout_constraintTop_toTopOf="parent"иapp:layout_constraintBottom_toBottomOf="parent". По горизонтали конечные точки находятся в крайнем левом и правом углах экрана.
Для более подробного ознакомления с различными элементами, которые поддерживает сцена движения, см. примеры MotionLayout .
Интерполированные атрибуты
В файле сцены движения элементы ConstraintSet могут содержать дополнительные атрибуты, которые интерполируются во время перехода. Помимо позиции и границ, MotionLayout интерполирует следующие атрибуты:
-
alpha -
visibility -
elevation -
rotation,rotationX,rotationY -
translationX,translationY,translationZ -
scaleX,scaleY
Пользовательские атрибуты
Внутри элемента <Constraint> можно использовать элемент <CustomAttribute> для указания перехода для атрибутов, которые не связаны напрямую с атрибутами позиции или View .
<Constraint android:id="@+id/button" ...> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/> </Constraint>
Объект <CustomAttribute> содержит два собственных атрибута:
-
motion:attributeNameявляется обязательным и должен соответствовать объекту с методами getter и setter. Методы getter и setter должны соответствовать определенному шаблону. Например, поддерживаетсяbackgroundColor, поскольку представление имеет базовые методыgetBackgroundColor()иsetBackgroundColor(). - Другой атрибут, который необходимо указать, зависит от типа значения. Выберите один из следующих поддерживаемых типов:
-
motion:customColorValueдля цветов -
motion:customIntegerValueдля целых чисел -
motion:customFloatValueдля чисел с плавающей запятой -
motion:customStringValueдля строк -
motion:customDimensionдля размеров -
motion:customBooleanдля логических значений
-
При указании пользовательского атрибута задайте значения конечной точки как в начальном, так и в конечном элементах <ConstraintSet> .
Изменить цвет фона
Основываясь на предыдущем примере, предположим, что вы хотите, чтобы цвета элемента управления менялись в процессе его движения, как показано на рисунке 2.
Добавьте элемент <CustomAttribute> к каждому элементу ConstraintSet , как показано в следующем фрагменте кода:
<ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF" /> </Constraint> </ConstraintSet>
Дополнительные атрибуты MotionLayout
Помимо атрибутов, приведенных в предыдущем примере, MotionLayout имеет и другие атрибуты, которые вы можете указать:
-
app:applyMotionScene="boolean"указывает, следует ли применять анимационную сцену. Значение по умолчанию для этого атрибута —true. -
app:showPaths="boolean"указывает, следует ли отображать траектории движения во время его выполнения. Значение по умолчанию для этого атрибута —false. -
app:progress="float"позволяет явно указать ход перехода. Вы можете использовать любое значение с плавающей запятой от0(начало перехода) до1(конец перехода). -
app:currentState="reference"позволяет указать конкретныйConstraintSet. -
app:motionDebugпозволяет отображать дополнительную отладочную информацию о движении. Возможные значения:"SHOW_PROGRESS","SHOW_PATH"или"SHOW_ALL".
Дополнительные ресурсы
Для получения дополнительной информации о MotionLayout см. следующие ресурсы:
- Расширенные возможности Android в Kotlin 03.2: анимация с помощью MotionLayout
- Примеры MotionLayout
- Примеры MotionLayout/ConstraintLayout на GitHub
- Введение в MotionLayout (часть I)
- Введение в MotionLayout (часть II)
- Введение в MotionLayout (часть III)
- Введение в MotionLayout (часть IV)
