Gérer l'animation des mouvements et des widgets avec MotionLayout

MotionLayout est un type de mise en page qui vous aide à gérer les animations de mouvement et de widget dans votre application. MotionLayout est une sous-classe de ConstraintLayout qui s'appuie sur ses nombreuses fonctionnalités de mise en page. Dans la bibliothèque ConstraintLayout, MotionLayout est disponible en tant que bibliothèque Support.

MotionLayout comble l'écart entre les transitions de mise en page et la gestion des mouvements complexes, en offrant une combinaison de fonctionnalités entre le framework d'animation des propriétés, TransitionManager et CoordinatorLayout.

Figure 1. Mouvements tactiles simples.

En plus de décrire les transitions entre les mises en page, MotionLayout vous permet d'animer toutes les propriétés de mise en page. De plus, il est intrinsèquement compatible avec les transitions consultables. Cela signifie que vous pouvez afficher instantanément n'importe quel point de la transition en fonction de certaines conditions, comme la saisie tactile. MotionLayout est également compatible avec les images clés, ce qui permet des transitions entièrement personnalisées en fonction de vos besoins.

MotionLayout est entièrement déclaratif, ce qui signifie que vous pouvez décrire toutes les transitions au format XML, quelle que soit leur complexité.

Considérations de conception

MotionLayout est destiné à déplacer, redimensionner et animer les éléments d'interface utilisateur avec lesquels les utilisateurs interagissent, tels que les boutons et les barres de titre. N'utilisez pas de mouvement dans votre application comme effet spécial sans frais. Utilisez-la pour aider les utilisateurs à comprendre ce que fait votre application. Pour en savoir plus sur la conception de votre application avec du mouvement, consultez la section Material Design Comprendre le mouvement.

Premiers pas

Suivez ces étapes pour commencer à utiliser MotionLayout dans votre projet.

  1. Ajoutez la dépendance ConstraintLayout:pour utiliser MotionLayout dans votre projet, ajoutez la dépendance ConstraintLayout 2.0 au fichier build.gradle de votre application. Si vous utilisez AndroidX, ajoutez la dépendance suivante:

    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")
    }
    
  2. Créez un fichier MotionLayout:MotionLayout est une sous-classe de ConstraintLayout. Vous pouvez donc transformer n'importe quelle ConstraintLayout existante en MotionLayout en remplaçant le nom de classe dans votre fichier de ressources de mise en page, comme illustré dans les exemples suivants:

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    Bibliothèque Support

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    Voici un exemple complet de fichier MotionLayout, qui définit la mise en page illustrée dans la figure 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>
            

    Bibliothèque Support

    <?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. Créez une MotionScene:dans l'exemple MotionLayout précédent, l'attribut app:layoutDescription fait référence à une scène d'animation. Une scène de mouvement est un fichier de ressources XML. Dans son élément racine <MotionScene>, une scène de mouvement contient toutes les descriptions de mouvement pour la mise en page correspondante. Pour séparer les informations de mise en page des descriptions de mouvement, chaque MotionLayout fait référence à une scène d'animation distincte. Les définitions de la scène de mouvement prévalent sur toutes les définitions similaires de la MotionLayout.

    Voici un exemple de fichier de scène de mouvement décrivant le mouvement horizontal de base de la figure 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>
        

    Remarques :

    • <Transition> contient la définition de base du mouvement.

      • motion:constraintSetStart et motion:constraintSetEnd sont des références aux extrémités du mouvement. Ces extrémités sont définies dans les éléments <ConstraintSet> plus loin dans la scène du mouvement.

      • motion:duration spécifie le nombre de millisecondes nécessaire au mouvement.

    • <OnSwipe> vous permet de créer une commande tactile pour le mouvement.

      • motion:touchAnchorId fait référence à la vue que l'utilisateur peut balayer et faire glisser.

      • motion:touchAnchorSide signifie que la vue est déplacée depuis le côté droit.

      • motion:dragDirection fait référence à la direction de progression du déplacement. Par exemple, motion:dragDirection="dragRight" signifie que la progression augmente à mesure que la vue est déplacée vers la droite.

    • <ConstraintSet> vous permet de définir les différentes contraintes décrivant votre mouvement. Dans cet exemple, un <ConstraintSet> est défini pour chaque extrémité de votre mouvement. Ces points de terminaison sont centrés verticalement à l'aide de app:layout_constraintTop_toTopOf="parent" et de app:layout_constraintBottom_toBottomOf="parent". Horizontalement, les points de terminaison se trouvent aux extrémités gauche et droite de l'écran.

    Pour obtenir plus de détails sur les différents éléments pris en charge par une scène de mouvement, consultez les exemples de MotionLayout.

Attributs interpolés

Dans un fichier de scène de mouvement, les éléments ConstraintSet peuvent contenir des attributs supplémentaires interpolés lors de la transition. En plus de la position et des limites, les attributs suivants sont interpolés par MotionLayout:

  • alpha
  • visibility
  • elevation
  • rotation, rotationX, rotationY
  • translationX, translationY, translationZ
  • scaleX, scaleY

Attributs personnalisés

Dans un élément <Constraint>, vous pouvez utiliser l'élément <CustomAttribute> pour spécifier une transition pour les attributs qui ne sont pas simplement liés aux attributs de position ou View.

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

Un élément <CustomAttribute> contient deux attributs:

  • motion:attributeName est requis et doit correspondre à un objet avec les méthodes getter et setter. Le getter et le setter doivent correspondre à un modèle spécifique. Par exemple, backgroundColor est compatible, car la vue contient les méthodes getBackgroundColor() et setBackgroundColor() sous-jacentes.
  • L'autre attribut que vous devez fournir est basé sur le type de valeur. Choisissez l'un des types compatibles suivants :
    • motion:customColorValue pour les couleurs
    • motion:customIntegerValue pour les entiers
    • motion:customFloatValue pour les flottants
    • motion:customStringValue pour les chaînes
    • motion:customDimension pour les dimensions
    • motion:customBoolean pour les valeurs booléennes

Lorsque vous spécifiez un attribut personnalisé, définissez les valeurs de point de terminaison dans les éléments <ConstraintSet> de début et de fin.

Modifier la couleur d'arrière-plan

Sur la base de l'exemple précédent, supposons que vous souhaitiez modifier les couleurs de la vue dans le cadre de son mouvement, comme illustré dans la figure 2.

Figure 2. La couleur d'arrière-plan de la vue change en fonction de ses déplacements.

Ajoutez un élément <CustomAttribute> à chaque élément ConstraintSet, comme indiqué dans l'extrait de code suivant:

<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>

Attributs MotionLayout supplémentaires

En plus des attributs de l'exemple précédent, MotionLayout possède d'autres attributs que vous pouvez spécifier:

  • app:applyMotionScene="boolean" indique si la scène de mouvement doit être appliquée. La valeur par défaut de cet attribut est true.
  • app:showPaths="boolean" indique si les trajectoires d'animation doivent être affichées pendant l'exécution du mouvement. La valeur par défaut de cet attribut est false.
  • app:progress="float" vous permet de spécifier explicitement la progression de la transition. Vous pouvez utiliser n'importe quelle valeur à virgule flottante comprise entre 0 (début de la transition) et 1 (fin de la transition).
  • app:currentState="reference" vous permet de spécifier un ConstraintSet spécifique.
  • app:motionDebug vous permet d'afficher des informations de débogage supplémentaires sur le mouvement. Les valeurs possibles sont "SHOW_PROGRESS", "SHOW_PATH" ou "SHOW_ALL".

Ressources supplémentaires

Pour en savoir plus sur MotionLayout, consultez les ressources suivantes: