MotionLayout
es un tipo de diseño que te ayuda a administrar las animaciones de movimiento y widgets en tu app. MotionLayout
es una subclase de ConstraintLayout
y se basa en sus capacidades de diseño enriquecido. Como parte de la biblioteca ConstraintLayout
, MotionLayout
está disponible como biblioteca de compatibilidad.
MotionLayout
cierra la brecha entre las transiciones de diseño y el control de movimiento complejo, lo que ofrece una combinación de funciones entre el framework de animación de propiedades, TransitionManager
y CoordinatorLayout
.
Además de describir las transiciones entre diseños, MotionLayout
te permite animar cualquier propiedad de diseño. Además, es inherentemente compatible con las transiciones que admiten búsquedas. Esto significa que puedes mostrar de forma instantánea cualquier punto dentro de la transición según alguna condición, como la entrada táctil. MotionLayout
también admite fotogramas clave, lo que permite realizar transiciones totalmente personalizadas para satisfacer tus necesidades.
MotionLayout
es totalmente declarativo, lo que significa que puedes describir cualquier transición en XML, sin importar qué tan compleja sea.
Consideraciones del diseño
MotionLayout
está diseñado para mover, cambiar el tamaño y animar los elementos de la IU con los que interactúan los usuarios, como botones y barras de título. No uses el movimiento en tu app como un efecto especial injustificado. Úsala para ayudar a los usuarios a comprender lo que hace tu app. Para obtener más información sobre cómo diseñar tu app con movimiento, consulta la sección de Material Design Cómo comprender el movimiento.
Comenzar
Sigue estos pasos para comenzar a usar MotionLayout
en tu proyecto.
-
Agrega la dependencia
ConstraintLayout
: para usarMotionLayout
en tu proyecto, agrega la dependenciaConstraintLayout
2.0 al archivobuild.gradle
de tu app. Si usas AndroidX, agrega la siguiente dependencia:Groovy
dependencies { implementation "androidx.constraintlayout:constraintlayout:2.2.0-alpha13" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13" }
Kotlin
dependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha13") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13") }
-
Crea un archivo
MotionLayout
:MotionLayout
es una subclase deConstraintLayout
, por lo que puedes transformar cualquierConstraintLayout
existente en unMotionLayout
reemplazando el nombre de clase en tu archivo de recursos de diseño, como se muestra en los siguientes ejemplos:AndroidX
<!-- before: ConstraintLayout --> <androidx.constraintlayout.widget.ConstraintLayout .../> <!-- after: MotionLayout --> <androidx.constraintlayout.motion.widget.MotionLayout .../>
Biblioteca de compatibilidad
<!-- before: ConstraintLayout --> <android.support.constraint.ConstraintLayout .../> <!-- after: MotionLayout --> <android.support.constraint.motion.MotionLayout .../>
A continuación, se incluye un ejemplo completo de un archivo
MotionLayout
, que define el diseño que se muestra en la figura 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>
Biblioteca de compatibilidad
<?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>
-
Crea un archivo MotionScene:en el ejemplo anterior de
MotionLayout
, el atributoapp:layoutDescription
hace referencia a una escena en movimiento. Una escena en movimiento es un archivo de recursos XML. Dentro de su elemento raíz<MotionScene>
, una escena de movimiento contiene todas las descripciones de movimiento para el diseño correspondiente. Para mantener la información de diseño separada de las descripciones de movimiento, cadaMotionLayout
hace referencia a una escena de movimiento separada. Las definiciones de la escena de movimiento tienen prioridad sobre cualquier definición similar deMotionLayout
.A continuación, se incluye un archivo de escena en movimiento de ejemplo en el que se describe el movimiento horizontal básico en la figura 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>
Ten en cuenta lo siguiente:
-
<Transition>
contiene la definición base del movimiento.-
motion:constraintSetStart
ymotion:constraintSetEnd
son referencias a los extremos del movimiento. Estos extremos se definen en los elementos<ConstraintSet>
más adelante en la escena de movimiento. -
motion:duration
especifica la cantidad de milisegundos que tarda en completarse el movimiento.
-
-
<OnSwipe>
te permite crear controles de tacto para el movimiento.-
motion:touchAnchorId
hace referencia a la vista que el usuario puede deslizar y arrastrar. -
motion:touchAnchorSide
significa que se está arrastrando la vista desde el lado derecho. -
motion:dragDirection
hace referencia a la dirección de progreso del arrastre. Por ejemplo,motion:dragDirection="dragRight"
significa que el progreso aumenta a medida que se arrastra la vista hacia la derecha.
-
-
<ConstraintSet>
es donde definirás las diversas restricciones que describen tu movimiento. En este ejemplo, se define un<ConstraintSet>
para cada extremo de tu movimiento. Estos extremos se centran de forma vertical medianteapp:layout_constraintTop_toTopOf="parent"
yapp:layout_constraintBottom_toBottomOf="parent"
. De manera horizontal, los extremos se encuentran en los lados izquierdo y derecho de la pantalla.
Para obtener un panorama más detallado de los distintos elementos que admite una escena en movimiento, consulta los ejemplos de MotionLayout.
-
Atributos interpolados
Dentro de un archivo de escena en movimiento, los elementos ConstraintSet
pueden contener atributos adicionales que se interpolan durante la transición. Además de la posición y los límites, MotionLayout
interpola los siguientes atributos:
alpha
visibility
elevation
rotation
,rotationX
,rotationY
translationX
,translationY
,translationZ
scaleX
,scaleY
Atributos personalizados
Dentro de un <Constraint>
, puedes usar el elemento <CustomAttribute>
para especificar una transición para los atributos que no están relacionados simplemente con la posición o los atributos View
.
<Constraint android:id="@+id/button" ...> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/> </Constraint>
Un <CustomAttribute>
contiene dos atributos propios:
motion:attributeName
es obligatorio y debe coincidir con un objeto que tenga métodos get y set. Los métodos get y set deben coincidir con un patrón específico. Por ejemplo, se admitebackgroundColor
, ya que la vista tiene métodosgetBackgroundColor()
ysetBackgroundColor()
subyacentes.- El otro atributo que debes proporcionar se basa en el tipo de valor. Elige entre los siguientes tipos admitidos:
motion:customColorValue
para los coloresmotion:customIntegerValue
para números enterosmotion:customFloatValue
para valores flotantesmotion:customStringValue
para stringsmotion:customDimension
para dimensionesmotion:customBoolean
para valores booleanos
Cuando especifiques un atributo personalizado, define los valores de extremo en los elementos <ConstraintSet>
de inicio y fin.
Cambiar el color del fondo
Partiendo del ejemplo anterior, supongamos que deseas que los colores de la vista cambien como parte de su movimiento, como se muestra en la Figura 2.
Agrega un elemento <CustomAttribute>
a cada elemento ConstraintSet
, como se muestra en el siguiente fragmento de código:
<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>
Atributos adicionales de MotionLayout
Además de los atributos del ejemplo anterior, MotionLayout
tiene otros atributos que quizás desees especificar:
app:applyMotionScene="boolean"
indica si se debe aplicar la escena de movimiento. El valor predeterminado para este atributo estrue
.app:showPaths="boolean"
indica si se deben mostrar las rutas de movimiento mientras se ejecuta el movimiento. El valor predeterminado para este atributo esfalse
.app:progress="float"
te permite especificar explícitamente el progreso de la transición. Puedes usar cualquier valor de punto flotante desde0
(el inicio de la transición) hasta1
(el final de la transición).app:currentState="reference"
te permite especificar unConstraintSet
específico.app:motionDebug
te permite mostrar información adicional de depuración sobre el movimiento. Los valores posibles son"SHOW_PROGRESS"
,"SHOW_PATH"
o"SHOW_ALL"
.
Recursos adicionales
Para obtener más información sobre MotionLayout
, consulta los siguientes recursos:
- Android en Kotlin 03.2 avanzado: Animación con MotionLayout
- Ejemplos de MotionLayout
- Muestras de MotionLayout/ConstraintLayout en GitHub
- Introducción a MotionLayout (parte I)
- Introducción a MotionLayout (parte II)
- Introducción a MotionLayout (parte III)
- Introducción a MotionLayout (parte IV)