Управляйте анимацией движения и виджетов с помощью MotionLayout

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

MotionLayout устраняет разрыв между переходами макета и сложной обработкой движений, предлагая сочетание функций между инфраструктурой анимации свойств , TransitionManager и CoordinatorLayout .

Рисунок 1. Базовое сенсорное управление движением.

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

MotionLayout полностью декларативен, что означает, что вы можете описать любые переходы в XML, независимо от их сложности.

Рекомендации по проектированию

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

Начать

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

  1. Добавьте зависимость ConstraintLayout : чтобы использовать MotionLayout в своем проекте, добавьте зависимость ConstraintLayout 2.0 в файл build.gradle вашего приложения. Если вы используете AndroidX, добавьте следующую зависимость:

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-beta01"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-beta01")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01")
    }
    
  2. Создайте файл 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>
            
  3. Создайте MotionScene: в предыдущем примере MotionLayout атрибут app:layoutDescription ссылается на сцену движения . Сцена движения — это файл ресурсов XML. В корневом элементе <MotionScene> сцена движения содержит все описания движения для соответствующего макета. Чтобы хранить информацию о макете отдельно от описаний движения, каждый MotionLayout ссылается на отдельную сцену движения. Определения в сцене движения имеют приоритет над любыми аналогичными определениями в 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 является обязательным и должен соответствовать объекту с помощью методов получения и установки. Геттер и сеттер должны соответствовать определенному шаблону. Например, поддерживается backgroundColor , поскольку представление имеет базовые методы getBackgroundColor() и setBackgroundColor() .
  • Другой атрибут, который вы должны предоставить, основан на типе значения. Выберите один из следующих поддерживаемых типов:
    • motion:customColorValue для цветов
    • motion:customIntegerValue для целых чисел
    • motion:customFloatValue для поплавков
    • motion:customStringValue для строк
    • motion:customDimension для размеров
    • motion:customBoolean для логических значений

При указании настраиваемого атрибута определите значения конечной точки как в начальном, так и в конечном элементах <ConstraintSet> .

Изменить цвет фона

Опираясь на предыдущий пример, предположим, что вы хотите, чтобы цвета представления менялись при его движении, как показано на рисунке 2.

Рисунок 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 см. в следующих ресурсах: