1. Avant de commencer
Cet atelier de programmation fait partie du cours Développement Android avancé en Kotlin. Vous tirerez pleinement parti de ce cours si vous suivez les ateliers de programmation dans l'ordre, mais ce n'est pas obligatoire. Tous les ateliers de programmation du cours sont listés sur la page de destination des ateliers de programmation avancés pour Android en Kotlin.
MotionLayout est une bibliothèque qui vous permet d'ajouter des animations enrichies à votre application Android. Il est basé sur ConstraintLayout, et vous permet d'animer tout ce que vous pouvez compiler à l'aide de ConstraintLayout.
Vous pouvez utiliser MotionLayout pour animer simultanément l'emplacement, la taille, la visibilité, la valeur alpha, la couleur, l'élévation, la rotation et d'autres attributs de plusieurs vues. À l'aide du code XML déclaratif, vous pouvez créer des animations coordonnées impliquant plusieurs vues, qui sont difficiles à réaliser avec du code.
Les animations sont un excellent moyen d'améliorer l'expérience d'une application. Vous pouvez utiliser des animations pour:
- Afficher les modifications : l'animation permet à l'utilisateur de suivre naturellement les modifications apportées à votre interface utilisateur.
- Attirez l'attention : utilisez des animations pour attirer l'attention sur des éléments importants de l'interface utilisateur.
- Créez de magnifiques graphismes : des mouvements de conception efficaces rendent les applications plus attrayantes.
Prérequis
Cet atelier de programmation s'adresse aux développeurs ayant une certaine expérience du développement Android. Avant de suivre cet atelier de programmation, vous devez:
- Apprenez à créer une application avec une activité et une mise en page de base, et à l'exécuter sur un appareil ou un émulateur à l'aide d'Android Studio. Familiarisez-vous avec
ConstraintLayout. Pour en savoir plus surConstraintLayout, consultez l'atelier de programmation sur la mise en page avec contrainte.
Objectifs de l'atelier
- Définir une animation avec
ConstraintSetsetMotionLayout - Animation basée sur des événements de déplacement
- Modifier l'animation avec
KeyPosition - Modifier les attributs avec
KeyAttribute - Exécuter des animations avec du code
- Animer des en-têtes réductibles avec
MotionLayout
Prérequis
- Android Studio 4.0 (l'éditeur
MotionLayoutne fonctionne qu'avec cette version d'Android Studio)
2. Premiers pas
Pour télécharger l'application exemple, vous pouvez :
Vous pouvez également cloner le dépôt GitHub à partir de la ligne de commande à l'aide de la commande suivante :
$ git clone https://github.com/googlecodelabs/motionlayout.git
3. Créer des animations avec MotionLayout
Tout d'abord, vous allez créer une animation qui déplace une vue du début vers le bas de l'écran en réponse à un clic de l'utilisateur.
Pour créer une animation à partir du code de démarrage, vous avez besoin des éléments principaux suivants:
- Un
MotionLayout,, qui est une sous-classe deConstraintLayout. Vous spécifiez toutes les vues à animer dans la baliseMotionLayout. - Un
MotionScene,, qui est un fichier XML qui décrit une animation pourMotionLayout. Transition,qui fait partie deMotionScenequi spécifie la durée de l'animation, le déclencheur et comment déplacer les vues.- Élément
ConstraintSetqui spécifie à la fois les contraintes start et end de la transition.
Examinons chacun de ces éléments l'un après l'autre, en commençant par MotionLayout.
Étape 1: Explorez le code existant
MotionLayout est une sous-classe de ConstraintLayout. Il prend donc en charge les mêmes fonctionnalités lors de l'ajout d'une animation. Pour utiliser MotionLayout, vous ajoutez une vue MotionLayout où vous utiliseriez ConstraintLayout..
- Dans
res/layout, ouvrezactivity_step1.xml.. Vous avez ici unConstraintLayoutcontenant un seulImageViewd'étoile, avec une teinte appliquée.
activity_step1.xml
<!-- initial code -->
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/red_star"
...
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Cette ConstraintLayout n'a aucune contrainte. Par conséquent, si vous exécutiez l'application maintenant, vous verrez l'affichage des étoiles sans contrainte, ce qui signifie qu'ils seraient positionnés dans un emplacement inconnu. Android Studio affiche un avertissement concernant l'absence de contraintes.
Étape 2: Passer à la mise en page de mouvement
Pour créer une animation à l'aide de MotionLayout,, vous devez convertir ConstraintLayout en MotionLayout.
Pour que votre mise en page utilise une scène de mouvement, elle doit pointer vers elle.
- Pour ce faire, ouvrez la surface de conception. Dans Android Studio 4.0, vous ouvrez la surface de conception à l'aide de l'icône de fractionnement ou de conception en haut à droite lorsque vous consultez un fichier XML de mise en page.

- Une fois que vous avez ouvert la surface de conception, effectuez un clic droit sur l'aperçu, puis sélectionnez Convert to MotionLayout (Convertir en MotionLayout).

Cela remplace la balise ConstraintLayout par une balise MotionLayout et ajoute un motion:layoutDescription à la balise MotionLayout qui pointe vers @xml/activity_step1_scene.
activity_step1**.xml**
<!-- explore motion:layoutDescription="@xml/activity_step1_scene" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/activity_step1_scene">
Une scène de mouvement est un fichier XML unique qui décrit une animation dans un MotionLayout.
Dès que vous convertissez votre élément en MotionLayout, la surface de conception affiche l'éditeur de mouvement

L'Éditeur de mouvement comprend trois nouveaux éléments d'interface utilisateur:
- Overview (Aperçu) : cette sélection modale vous permet de sélectionner différentes parties de l'animation. Dans cette image, la
ConstraintSetstartest sélectionnée. Vous pouvez également sélectionner la transition entrestartetenden cliquant sur la flèche entre les éléments. - Section : sous l'aperçu, une fenêtre de section change en fonction de l'élément actuellement sélectionné. Dans cette image, les informations
ConstraintSetstarts'affichent dans la fenêtre de sélection. - Attribut : le panneau des attributs s'affiche et vous permet de modifier les attributs de l'élément sélectionné depuis la fenêtre de présentation ou de sélection. Dans cette image, il s'agit des attributs du
ConstraintSetstart.
Étape 3: Définissez les contraintes de début et de fin
Toutes les animations peuvent être définies en termes de début et de fin. Le début décrit ce à quoi ressemble l'écran avant l'animation et la fin décrit ce à quoi ressemble l'écran une fois l'animation terminée. MotionLayout est responsable de l'animation entre l'état de début et l'état de fin (au fil du temps).
MotionScene utilise une balise ConstraintSet pour définir les états de début et de fin. Comme son nom l'indique, une ConstraintSet est un ensemble de contraintes qui peuvent être appliquées aux vues. Cela inclut les contraintes de largeur, de hauteur et de ConstraintLayout. Il inclut également certains attributs tels que alpha. Il ne contient pas les vues elles-mêmes, mais uniquement les contraintes qui s'appliquent à ces vues.
Toutes les contraintes spécifiées dans un ConstraintSet remplacent celles spécifiées dans le fichier de mise en page. Si vous définissez des contraintes à la fois dans la mise en page et dans MotionScene, seules celles de MotionScene sont appliquées.
Au cours de cette étape, vous allez faire en sorte que l'affichage des étoiles commence en haut au début de l'écran et se termine en bas de l'écran.
Vous pouvez effectuer cette étape dans l'Éditeur de mouvement ou en modifiant directement le texte de activity_step1_scene.xml.
- Sélectionnez le ConstraintSet
startdans le panneau de présentation

- Dans le panneau de sélection, sélectionnez
red_star. La source s'affiche actuellement pourlayout, ce qui signifie qu'il n'est pas limité dans cetteConstraintSet. Utilisez l'icône en forme de crayon en haut à droite pour créer une contrainte.

- Vérifiez que
red_staraffiche une source destartlorsquestartConstraintSetest sélectionné dans le panneau d'aperçu. - Dans le panneau "Attributes" (Attributs), avec
red_starsélectionné dansstartConstraintSet, ajoutez une contrainte en haut et commencez par cliquer sur les boutons + bleus.

- Ouvrez
xml/activity_step1_scene.xmlpour afficher le code généré par l'Éditeur de mouvement pour cette contrainte.
activity_step1_scene.xml
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
Le id de ConstraintSet est @id/start et spécifie toutes les contraintes à appliquer à toutes les vues de MotionLayout. Comme ce MotionLayout ne comporte qu'une seule vue, il n'a besoin que d'un Constraint.
Le Constraint dans ConstraintSet spécifie l'ID de la vue qu'il contraint, @id/red_star défini dans activity_step1.xml. Il est important de noter que les balises Constraint ne spécifient que des contraintes et des informations de mise en page. La balise Constraint ne sait pas qu'elle est appliquée à un ImageView.
Cette contrainte spécifie la hauteur, la largeur et les deux autres contraintes requises pour contraindre la vue red_star au début de son parent.
- Sélectionnez le ConstraintSet
enddans le panneau de présentation.

- Suivez la même procédure que précédemment pour ajouter un
Constraintpourred_stardans leendConstraintSet. - Pour utiliser l'Éditeur de mouvement afin d'effectuer cette étape, ajoutez une contrainte à
bottometenden cliquant sur les boutons + bleus.

- Le code XML se présente comme suit:
activitiy_step1_scene.xml
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
Tout comme @id/start, ce ConstraintSet possède un seul Constraint sur @id/red_star. Cette fois, l'application applique une contrainte sur l'extrémité inférieure de l'écran.
Il n'est pas nécessaire de les nommer @id/start et @id/end, mais cette opération est pratique.
Étape 4: Définissez une transition
Chaque MotionScene doit également inclure au moins une transition. Une transition définit chaque partie d'une animation, du début à la fin.
Une transition doit spécifier des ConstraintSet de début et de fin. Une transition peut également spécifier d'autres manières de modifier l'animation, par exemple sa durée d'exécution ou la manière de l'animer en faisant glisser des vues.
- L'Éditeur de mouvement crée une transition par défaut pour nous lors de la création du fichier MotionScene. Ouvrez
activity_step1_scene.xmlpour voir la transition générée.
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
C'est tout ce dont MotionLayout a besoin pour créer une animation. Examiner chaque attribut:
constraintSetStartsera appliqué aux vues au début de l'animation.constraintSetEndsera appliqué aux vues à la fin de l'animation.durationspécifie la durée de l'animation en millisecondes.
MotionLayout recherche alors un chemin entre les contraintes de début et de fin et l'anime pendant la durée spécifiée.
Étape 5: Prévisualiser l'animation dans l'Éditeur de mouvement

Animation:vidéo de lecture d'un aperçu de transition dans l'éditeur de mouvement
- Ouvrez l'Éditeur de mouvement, puis sélectionnez la transition en cliquant sur la flèche entre
startetenddans le panneau de présentation.

- Le panneau selection (sélection) affiche les commandes de lecture et une barre de lecture lorsqu'une transition est sélectionnée. Cliquez sur le bouton de lecture ou faites glisser la position actuelle pour prévisualiser l'animation.

Étape 6: Ajoutez un gestionnaire de clics
Vous devez trouver un moyen de lancer l'animation. Pour ce faire, vous pouvez faire en sorte que MotionLayout réponde aux événements de clic sur @id/red_star.
- Ouvrez l'éditeur de mouvement et sélectionnez la transition en cliquant sur la flèche entre le début et la fin dans le panneau de présentation.

- Cliquez sur
Créer un gestionnaire de clics ou de balayages dans la barre d'outils du panneau de présentation . Cette action ajoute un gestionnaire qui lancera une transition. - Sélectionnez Gestionnaire de clics dans la fenêtre pop-up.

- Définissez View To Click (Afficher pour cliquer) sur
red_star.

- Cliquez sur Ajouter. Dans l'Éditeur de mouvement, le gestionnaire de clics est représenté par un petit point au niveau de la transition.

- Une fois la transition sélectionnée dans le panneau "Overview" (Aperçu), ajoutez un attribut
clickActiondetoggleau gestionnaire OnClick que vous venez d'ajouter dans le panneau des attributs.

- Ouvrez
activity_step1_scene.xmlpour voir le code généré par l'Éditeur de mouvement
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/red_star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
Transition indique à MotionLayout d'exécuter l'animation en réponse aux événements de clic à l'aide d'une balise <OnClick>. Examiner chaque attribut:
targetIdest la vue à surveiller pour les clics.clickActionsurtogglepassera de l'état de début à l'état de fin lors d'un clic. Vous pouvez découvrir d'autres options pourclickActiondans la documentation.
- Exécutez votre code, cliquez sur l'étape 1, puis sur l'étoile rouge et observez l'animation.
Étape 5: Les animations en action
Exécutez l'application ! Votre animation doit s'exécuter lorsque vous cliquez sur l'étoile.

Le fichier de scène de mouvement finalisé définit un élément Transition qui pointe vers une ConstraintSet de début et de fin.
Au début de l'animation (@id/start), l'icône en forme d'étoile se limite au début supérieur de l'écran. À la fin de l'animation (@id/end), l'icône en forme d'étoile se trouve au bas de l'écran.
<?xml version="1.0" encoding="utf-8"?>
<!-- Describe the animation for activity_step1.xml -->
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
</MotionScene>
4. Animation basée sur des événements de déplacement
Au cours de cette étape, vous allez créer une animation qui répond à un événement de déplacement de l'utilisateur (lorsque l'utilisateur balaie l'écran) pour exécuter l'animation. MotionLayout prend en charge le suivi des événements tactiles pour déplacer les vues, ainsi que des gestes de glissement d'un geste vif basés sur les lois de la physique pour fluidifier le mouvement.
Étape 1: Inspectez le code initial
- Pour commencer, ouvrez le fichier de mise en page
activity_step2.xml, qui contient déjà unMotionLayout. Examinez le code.
activity_step2.xml
<!-- initial code -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/step2" >
<ImageView
android:id="@+id/left_star"
...
/>
<ImageView
android:id="@+id/right_star"
...
/>
<ImageView
android:id="@+id/red_star"
...
/>
<TextView
android:id="@+id/credits"
...
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Cette mise en page définit toutes les vues de l'animation. Les icônes à trois étoiles ne sont pas limitées dans la mise en page, car elles sont animées dans la scène de mouvement.
Des contraintes sont appliquées au crédit TextView, car il reste au même endroit pendant toute l'animation et ne modifie aucun attribut.
Étape 2: Animez la scène
Comme la dernière animation, elle est définie par une ConstraintSet, de début et de fin, ainsi qu'une Transition.
Définit le ConstraintSet de départ.
- Ouvrez la scène de mouvement
xml/step2.xmlpour définir l'animation. - Ajoutez les contraintes pour la contrainte de départ
start. Au début, les trois étoiles sont centrées en bas de l'écran. Les étoiles de droite et de gauche ont une valeuralphade0.0, ce qui signifie qu'elles sont totalement transparentes et masquées.
step2.xml
<!-- TODO apply starting constraints -->
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
Dans cette ConstraintSet, vous spécifiez une valeur Constraint pour chacune des étoiles. Chaque contrainte sera appliquée par MotionLayout au début de l'animation.
Chaque vue en étoile est centrée en bas de l'écran en fonction des contraintes de début, de fin et de bas. Les deux étoiles @id/left_star et @id/right_star ont toutes deux une valeur alpha supplémentaire qui les rend invisibles et qui sera appliquée au début de l'animation.
Les ensembles de contraintes start et end définissent le début et la fin de l'animation. Une contrainte appliquée au début (motion:layout_constraintStart_toStartOf, par exemple) contraint le début d'une vue au début d'une autre. Cela peut prêter à confusion au début, car le nom start est utilisé à la fois et dans le contexte de contraintes. Pour faire la distinction, le start dans layout_constraintStart fait référence au "début" de la vue, qui est celle de gauche
dans une langue de gauche à droite et celle de droite dans une langue de droite à gauche. L'ensemble de contraintes start fait référence au début de l'animation.
Définir le ConstraintSet final
- Définissez la contrainte de fin afin d'utiliser une chaîne pour positionner les trois étoiles sous
@id/credits. De plus, la valeur de fin de l'alphades étoiles gauche et droite sera définie sur1.0.
step2.xml
<!-- TODO apply ending constraints -->
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintHorizontal_chainStyle="packed"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toStartOf="@id/red_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toEndOf="@id/left_star"
motion:layout_constraintEnd_toStartOf="@id/right_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintStart_toEndOf="@id/red_star"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toBottomOf="@id/credits" />
</ConstraintSet>
Au final, les vues s'étendent et s'étendent à partir du centre au fur et à mesure de leur animation.
De plus, comme la propriété alpha est définie sur @id/right_start et @id/left_star dans les deux vues ConstraintSets, les deux vues s'affichent en fondu à mesure que l'animation progresse.
Animation basée sur le balayage de l'utilisateur
MotionLayout peut suivre les événements de déplacement de l'utilisateur, ou un balayage, pour créer un "glissement d'un geste vif" basé sur les lois de la physique de l'animation. Cela signifie que les vues se poursuivront si l'utilisateur les déplace et ralentiront comme le ferait un objet physique lorsqu'il roulerait sur une surface. Vous pouvez ajouter ce type d'animation avec une balise OnSwipe dans Transition.
- Remplacez TODO pour ajouter une balise
OnSwipepar<OnSwipe motion:touchAnchorId="@id/red_star" />.
step2.xml
<!-- TODO add OnSwipe tag -->
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end">
<!-- MotionLayout will track swipes relative to this view -->
<OnSwipe motion:touchAnchorId="@id/red_star" />
</Transition>
OnSwipe contient quelques attributs, le plus important étant touchAnchorId.
touchAnchorIdest la vue suivie qui se déplace en réponse à un appui.MotionLayoutmaintient cette vue à la même distance du doigt qui balaie l'écran.touchAnchorSidedétermine quel côté de la vue doit être suivi. Ceci est important pour les vues qui sont redimensionnées, qui suivent des chemins complexes ou dont un côté se déplace plus rapidement que l'autre.dragDirectiondétermine la direction de l'animation (vers le haut, le bas, la gauche ou la droite).
Lorsque MotionLayout écoute des événements de déplacement, l'écouteur est enregistré dans la vue MotionLayout, et non dans la vue spécifiée par touchAnchorId. Lorsqu'un utilisateur commence un geste n'importe où sur l'écran, MotionLayout maintient constante la distance entre son doigt et le touchAnchorSide de la vue touchAnchorId. Par exemple, si l'utilisateur touche 100 dp du côté de l'ancre, MotionLayout l'éloigne de 100 dp de son doigt pendant toute l'animation.
Essayer
- Exécutez à nouveau l'application et ouvrez l'écran de l'étape 2. L'animation s'affiche.
- Essayez de faire glisser d'un geste vif Vous pouvez aussi relâcher le doigt au milieu de l'animation pour découvrir comment
MotionLayoutaffiche des animations basées sur la physique des fluides.

MotionLayout peut animer des conceptions très différentes à l'aide des fonctionnalités de ConstraintLayout pour créer des effets riches.
Dans cette animation, les trois vues sont positionnées par rapport à leur parent en bas de l'écran pour commencer. À la fin, les trois vues sont positionnées par rapport à @id/credits dans une chaîne.
Malgré ces mises en page très différentes, MotionLayout crée une animation fluide entre le début et la fin.
5. Modifier un chemin d'accès
Au cours de cette étape, vous allez créer une animation qui suit un tracé complexe pendant l'animation et anime les crédits pendant le mouvement. MotionLayout peut modifier le chemin qu'une vue prendra entre le début et la fin à l'aide d'un KeyPosition.
Étape 1: Explorez le code existant
- Ouvrez
layout/activity_step3.xmletxml/step3.xmlpour afficher la mise en page et la scène d'animation existantes.ImageViewetTextViewaffichent la lune et le texte des crédits. - Ouvrez le fichier de scène de mouvement (
xml/step3.xml). Vous constatez qu'un élémentTransitionde@id/startà@id/endest défini. L'animation déplace l'image de lune du coin inférieur gauche de l'écran vers le bas à droite de l'écran à l'aide de deuxConstraintSets. Le texte des crédits apparaît en fondu dealpha="0.0"àalpha="1.0"à mesure que la lune se déplace. - Exécutez l'application maintenant et sélectionnez Étape 3. Vous verrez que la Lune suit un trajet linéaire (ou une ligne droite) du début à la fin lorsque vous cliquez dessus.
Étape 2: Activer le débogage du chemin d'accès
Avant d'ajouter un arc au mouvement de la Lune, il est utile d'activer le débogage du trajet dans MotionLayout.
Pour développer des animations complexes avec MotionLayout, vous pouvez dessiner le chemin d'animation de chaque vue. Cette fonctionnalité est utile lorsque vous souhaitez visualiser votre animation et affiner les moindres détails du mouvement.
- Pour activer les chemins de débogage, ouvrez
layout/activity_step3.xmlet ajoutezmotion:motionDebug="SHOW_PATH"à la baliseMotionLayout.
activity_step3.xml
<!-- Add motion:motionDebug="SHOW_PATH" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:motionDebug="SHOW_PATH" >
Après avoir activé le débogage du chemin d'accès, lorsque vous réexécuterez l'application, les chemins de toutes les vues s'afficheront à l'aide d'une ligne en pointillés.

- Les cercles représentent la position de début ou de fin d'une vue.
- Les lignes représentent le trajet d'une vue.
- Les losanges représentent un
KeyPositionqui modifie le tracé.
Par exemple, dans cette animation, le cercle central correspond à la position du texte des crédits.
Étape 3: Modifiez le chemin d'accès
Toutes les animations de MotionLayout sont définies par un élément ConstraintSet de début et de fin qui définit l'apparence de l'écran avant le début et après la fin de l'animation. Par défaut, MotionLayout trace un tracé linéaire (une ligne droite) entre les positions de début et de fin de chaque vue qui change de position.
Pour construire des tracés complexes comme l'arc de la lune dans cet exemple, MotionLayout utilise un KeyPosition afin de modifier le trajet emprunté par une vue entre le début et la fin.
- Ouvrez
xml/step3.xmlet ajoutez unKeyPositionà la scène. La baliseKeyPositionest placée à l'intérieur de la baliseTransition.

step3.xml
<!-- TODO: Add KeyFrameSet and KeyPosition -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
Un KeyFrameSet est un enfant d'un Transition. Il s'agit d'un ensemble de tous les KeyFrames, tels que KeyPosition, qui doivent être appliqués pendant la transition.
Étant donné que MotionLayout calcule le trajet de la Lune entre le début et la fin, il modifie le tracé en fonction de la valeur KeyPosition spécifiée dans le KeyFrameSet. Vous pouvez voir comment cela modifie le chemin d'accès en exécutant à nouveau l'application.
Un élément KeyPosition comporte plusieurs attributs qui décrivent la manière dont il modifie le chemin d'accès. Voici les plus importants:
framePositionest un nombre compris entre 0 et 100. Il définit à quel moment, dans l'animation, ceKeyPositiondoit être appliqué, 1 correspondant à 1% pendant l'animation et 99 à 99% pendant l'animation. Ainsi, si la valeur est de 50, vous l'appliquez au milieu.motionTargetest la vue pour laquelle cetteKeyPositionmodifie le chemin.keyPositionTypeest la façon dont cetteKeyPositionmodifie le chemin d'accès. Il peut s'agir deparentRelative,pathRelativeoudeltaRelative(comme expliqué à l'étape suivante).percentX | percentYcorrespond au degré de modification du chemin àframePosition(valeurs comprises entre 0,0 et 1,0, avec des valeurs négatives et des valeurs supérieures à 1 autorisées).
Voici comment procéder : "À framePosition, modifiez la trajectoire de motionTarget en la déplaçant de percentX ou de percentY selon les coordonnées déterminées par keyPositionType.
Par défaut, MotionLayout arrondit tous les angles introduits en modifiant le tracé. Si vous regardez l'animation que vous venez de créer, vous pouvez voir que la lune suit une trajectoire incurvée au niveau du virage. C'est ce que vous souhaitez pour la plupart des animations. Si ce n'est pas le cas, vous pouvez spécifier l'attribut curveFit pour la personnaliser.
Essayer
Si vous exécutez à nouveau l'application, l'animation de cette étape s'affiche.

La Lune suit un arc car elle traverse l'KeyPosition spécifié dans l'Transition.
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
Vous pouvez lire ce KeyPosition comme suit : "À framePosition 50 (à mi-chemin de l'animation), modifiez le tracé de motionTarget @id/moon en le déplaçant de 50% Y (à mi-chemin vers le bas de l'écran) en fonction des coordonnées déterminées par parentRelative (l'ensemble du MotionLayout)."
Ainsi, à la moitié de l'animation, la lune doit traverser un KeyPosition situé à 50% de l'écran. Ce KeyPosition ne modifie pas du tout le mouvement X. La lune continuera donc d'aller horizontalement du début à la fin. MotionLayout trouvera un trajet fluide qui traverse cette KeyPosition en se déplaçant entre le début et la fin.
Si vous regardez attentivement, le texte des crédits est limité par la position de la lune. Pourquoi ne se déplace-t-elle pas verticalement ?

<Constraint
android:id="@id/credits"
...
motion:layout_constraintBottom_toBottomOf="@id/moon"
motion:layout_constraintTop_toTopOf="@id/moon"
/>
Il s'avère que, même si vous modifiez le trajet que suit la Lune, ses positions de début et de fin ne la déplacent pas verticalement. KeyPosition ne modifie pas la position de début ni de fin. Le texte des crédits est donc limité à la position finale de la lune.
Si vous voulez que les crédits se déplacent avec la lune, vous pouvez ajouter un KeyPosition aux crédits ou modifier les contraintes de début sur @id/credits.
Dans la section suivante, vous découvrirez les différents types de keyPositionType dans MotionLayout.
6. Comprendre le keyPositionType
Lors de la dernière étape, vous avez utilisé un keyPosition de type parentRelative pour décaler le chemin de 50% de l'écran. L'attribut keyPositionType détermine la façon dont MotionLayout modifiera le tracé en fonction de percentX ou de percentY.
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
Il existe trois types de keyPosition différents: parentRelative, pathRelative et deltaRelative. La spécification d'un type modifie le système de coordonnées par lequel les valeurs percentX et percentY sont calculées.
Qu'est-ce qu'un système de coordonnées ?
Un système de coordonnées permet de spécifier un point dans l'espace. Ils sont également utiles pour décrire une position à l'écran.
Les systèmes de coordonnées MotionLayout sont un système de coordonnées cartésien. Cela signifie qu'elles ont un axe X et un axe Y défini par deux lignes perpendiculaires. La principale différence réside dans la position de l'axe X sur l'écran (l'axe Y est toujours perpendiculaire à l'axe X).
Tous les systèmes de coordonnées de MotionLayout utilisent des valeurs comprises entre 0.0 et 1.0 sur les axes X et Y. Ils autorisent les valeurs négatives et les valeurs supérieures à 1.0. Par exemple, une valeur percentX de -2.0 signifierait d'aller deux fois dans le sens opposé de l'axe X.
Si cela ressemble un peu trop au cours d'algèbre, regardez les images ci-dessous !
parentRelative coordonnées

L'élément keyPositionType de parentRelative utilise le même système de coordonnées que l'écran. Elle définit (0, 0) en haut à gauche de l'ensemble de la MotionLayout et (1, 1) en bas à droite.
Vous pouvez utiliser parentRelative chaque fois que vous souhaitez créer une animation qui se déplace sur l'intégralité de la MotionLayout, comme l'arc lunaire dans cet exemple.
Toutefois, si vous souhaitez modifier un tracé par rapport au mouvement, par exemple pour la rendre légèrement incurvée, les deux autres systèmes de coordonnées sont plus adaptés.
Coordonnées deltaRelative

Delta est un terme mathématique qui désigne le changement. deltaRelative est donc une façon de dire "changer la relation relative". Dans deltaRelativecoordonnées, (0,0) correspond à la position de départ de la vue et (1,1) à la position de fin. Les axes X et Y sont alignés avec l'écran.
L'axe X est toujours horizontal à l'écran et l'axe Y est toujours vertical. Par rapport à parentRelative, la principale différence est que les coordonnées décrivent uniquement la partie de l'écran dans laquelle la vue est déplacée.
deltaRelative est un système de coordonnées idéal pour contrôler les mouvements horizontal ou vertical de manière isolée. Par exemple, vous pouvez créer une animation qui termine uniquement son mouvement vertical (Y) à 50 % et continue à s'animer horizontalement (X).
Coordonnées pathRelative

Le dernier système de coordonnées de MotionLayout est pathRelative. Elle est très différente des deux autres, car l'axe X suit la trajectoire d'animation du début à la fin. (0,0) correspond donc à la position de départ et (1,0) à la position de fin.
Pourquoi le choisir ? C'est assez surprenant à première vue, d'autant plus que ce système de coordonnées n'est même pas aligné sur celui de l'écran.
Il s'avère que pathRelative est très utile dans plusieurs cas.
- Accélérez, ralentissez ou arrêtez une vue pendant une partie de l'animation. Étant donné que la dimension X correspondra toujours exactement au chemin emprunté par la vue, vous pouvez utiliser un
KeyPositionpathRelativepour modifier laframePositionatteinte à un point particulier de ce chemin. Ainsi, unKeyPositionàframePosition="50"avec unepercentX="0.1"obligerait l'animation à mettre 50% du temps à parcourir les 10 premiers% du mouvement. - Ajouter un arc subtil à un tracé Étant donné que la dimension Y est toujours perpendiculaire au mouvement, la modification de Y modifie la trajectoire en courbe par rapport au mouvement global.
- Ajouter une deuxième dimension lorsque
deltaRelativene fonctionne pas. Pour un mouvement entièrement horizontal et vertical,deltaRelativene crée qu'une seule dimension utile. Cependant,pathRelativecrée toujours des coordonnées X et Y utilisables.
À l'étape suivante, vous allez apprendre à créer des chemins d'accès encore plus complexes en utilisant plusieurs KeyPosition.
7. Construire des chemins complexes
L'animation créée à la dernière étape crée une courbe lisse, mais la forme pourrait ressembler davantage à la lune.
Modifier un tracé avec plusieurs éléments KeyPosition
MotionLayout peut modifier davantage un tracé en définissant autant de KeyPosition que nécessaire pour générer un mouvement. Pour cette animation, vous allez construire un arc, mais vous pouvez faire sauter la lune de haut en bas au milieu de l'écran, si vous le souhaitez.
- Ouvrez
xml/step4.xml. Vous voyez qu'il possède les mêmes vues et leKeyFrameque vous avez ajouté à la dernière étape. - Pour arrondir le haut de la courbe, ajoutez deux autres
KeyPositionsau tracé de@id/moon: un juste avant qu'elle atteigne le sommet et une autre après.

step4.xml
<!-- TODO: Add two more KeyPositions to the KeyFrameSet here -->
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
Ces KeyPositions seront appliqués à 25% et 75% du chemin d'accès de l'animation, et entraîneront le déplacement de @id/moon sur un tracé situé à 60% du haut de l'écran. Combiné à l'KeyPosition existant à 50%, cela crée un arc lisse que la Lune peut suivre.
Dans MotionLayout, vous pouvez ajouter autant de KeyPositions que nécessaire pour obtenir la trajectoire d'animation souhaitée. MotionLayout appliquera chaque KeyPosition à la valeur framePosition spécifiée et déterminera comment créer un mouvement lisse qui traverse toutes les KeyPositions.
Essayer
- Exécutez à nouveau l'application. Passez à l'étape 4 pour voir l'animation en action. Lorsque vous cliquez sur la Lune, elle suit son tracé du début à la fin, en passant par chaque
KeyPositionspécifié dans leKeyFrameSet.
Explorer par vous-même
Avant de passer à d'autres types de KeyFrame, essayez d'ajouter d'autres KeyPositions à KeyFrameSet pour voir quels types d'effets vous pouvez créer en utilisant simplement KeyPosition.
Voici un exemple qui montre comment créer un tracé complexe qui se déplace dans les deux sens pendant l'animation.

step4.xml
<!-- Complex paths example: Dancing moon -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
motion:percentX="0.3"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
</KeyFrameSet>
Une fois que vous avez fini d'explorer KeyPosition, vous allez passer à d'autres types de KeyFrames à l'étape suivante.
8. Modification d'attributs pendant le mouvement
Pour créer des animations dynamiques, vous devez souvent modifier la size, la rotation ou la alpha des vues à mesure que l'animation progresse. MotionLayout permet d'animer de nombreux attributs sur n'importe quelle vue à l'aide d'un KeyAttribute.
Au cours de cette étape, vous allez utiliser KeyAttribute pour définir l'échelle de lune et la faire pivoter. Vous allez également utiliser un KeyAttribute pour retarder l'affichage du texte jusqu'à ce que la Lune ait presque terminé son trajet.
Étape 1: Redimensionnez et faites pivoter avec KeyAttribute
- Ouvrez
xml/step5.xml, qui contient la même animation que celle créée à la dernière étape. Pour plus de variété, cet écran utilise une image de l'espace différente comme arrière-plan. - Pour agrandir et faire pivoter la lune, ajoutez deux balises
KeyAttributedansKeyFrameSetàkeyFrame="50"etkeyFrame="100"

step5.xml
<!-- TODO: Add KeyAttributes to rotate and resize @id/moon -->
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon"
android:scaleY="2.0"
android:scaleX="2.0"
android:rotation="-360"
/>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon"
android:rotation="-720"
/>
Ces KeyAttributes sont appliquées à 50% et 100% de l'animation. La première KeyAttribute à 50% se produira en haut de l'arc, et entraînera le doublement de la taille de la vue et une rotation de -360 degrés (ou un cercle complet). Le deuxième KeyAttribute termine la deuxième rotation à -720 degrés (deux cercles complets) et réduit la taille à la taille normale, car les valeurs scaleX et scaleY sont définies par défaut sur 1,0.
Tout comme une KeyPosition, un KeyAttribute utilise framePosition et motionTarget pour spécifier quand appliquer le KeyFrame et quelle vue modifier. MotionLayout effectue une interpolation entre KeyPositions pour créer des animations fluides.
KeyAttributes acceptent les attributs qui peuvent être appliqués à toutes les vues. Ils sont compatibles avec la modification des attributs de base tels que visibility, alpha ou elevation. Vous pouvez également modifier la rotation comme vous le faites ici, effectuer une rotation en trois dimensions avec rotateX et rotateY, redimensionner la taille avec scaleX et scaleY, ou traduire la position de la vue en X, Y ou Z.
Étape 2: Retardez l'affichage des crédits
L'un des objectifs de cette étape consiste à mettre à jour l'animation afin que le texte des crédits n'apparaisse pas tant que l'animation n'est pas entièrement terminée.
- Pour retarder l'affichage des crédits, définissez une autre
KeyAttributequi garantit quealpharestera sur 0 jusqu'àkeyPosition="85".MotionLayouteffectuera toujours une transition fluide de la version alpha de 0 à 100, mais sur les 15% restants de l'animation.
step5.xml
<!-- TODO: Add KeyAttribute to delay the appearance of @id/credits -->
<KeyAttribute
motion:framePosition="85"
motion:motionTarget="@id/credits"
android:alpha="0.0"
/>
Ce KeyAttribute conserve la alpha de @id/credits à 0,0 pour les premiers 85% de l'animation. Puisqu'elle commence à une valeur alpha de 0, elle sera invisible pendant les premiers 85% de l'animation.
L'effet final de cette KeyAttribute est que les crédits apparaissent vers la fin de l'animation. Cela donne l'impression qu'ils sont coordonnés avec la Lune qui s'installe dans le coin droit de l'écran.
En décalant les animations d'une vue pendant qu'une autre se déplace ainsi, vous pouvez créer des animations impressionnantes et dynamiques pour l'utilisateur.
Essayer
- Exécutez à nouveau l'application et passez à l'étape 5 pour voir l'animation en action. Lorsque vous cliquez sur la lune, elle suit son trajet du début à la fin, en passant par chaque
KeyAttributespécifié dans lesKeyFrameSet.

Comme vous faites pivoter la Lune de deux cercles complets, elle effectuera désormais un double retournement, et les crédits retarderont leur affichage jusqu'à ce que l'animation soit presque terminée.
Explorer par vous-même
Avant de passer au type final de KeyFrame, essayez de modifier d'autres attributs standards dans KeyAttributes. Par exemple, essayez de remplacer rotation par rotationX pour voir l'animation générée.
Voici une liste des attributs standards que vous pouvez essayer:
android:visibilityandroid:alphaandroid:elevationandroid:rotationandroid:rotationXandroid:rotationYandroid:scaleXandroid:scaleYandroid:translationXandroid:translationYandroid:translationZ
9. Modifier des attributs personnalisés
Les animations enrichies impliquent la modification de la couleur ou d'autres attributs d'une vue. Bien que MotionLayout puisse utiliser un KeyAttribute pour modifier n'importe quel attribut standard listé dans la tâche précédente, vous utilisez un CustomAttribute pour spécifier tout autre attribut.
Un CustomAttribute peut être utilisé pour définir n'importe quelle valeur associée à un setter. Par exemple, vous pouvez définir le paramètre backgroundColor sur une vue à l'aide d'un CustomAttribute. MotionLayout utilisera la réflexion pour trouver le setter, puis l'appellera à plusieurs reprises pour animer la vue.
Au cours de cette étape, vous allez utiliser un CustomAttribute pour définir l'attribut colorFilter sur la Lune afin de créer l'animation ci-dessous.

Définir des attributs personnalisés
- Pour commencer, ouvrez
xml/step6.xml, qui contient la même animation que celle créée à l'étape précédente. - Pour que la lune change de couleur, ajoutez deux
KeyAttributeavec unCustomAttributedans leKeyFrameSetàkeyFrame="0",keyFrame="50"etkeyFrame="100".

step6.xml
<!-- TODO: Add Custom attributes here -->
<KeyAttribute
motion:framePosition="0"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFB612"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
Vous ajoutez un CustomAttribute dans un KeyAttribute. Le CustomAttribute sera appliqué au framePosition spécifié par KeyAttribute.
Dans CustomAttribute, vous devez spécifier un attributeName et une valeur à définir.
motion:attributeNameest le nom du setter qui sera appelé par cet attribut personnalisé. Dans cet exemple,setColorFiltersurDrawablesera appelé.motion:custom*Valueest une valeur personnalisée dont le type est indiqué dans le nom. Dans cet exemple, la valeur personnalisée est une couleur spécifiée.
Les valeurs personnalisées peuvent avoir l'un des types suivants:
- Couleur
- Entier
- Float
- Chaîne
- Dimension
- Booléen
À l'aide de cette API, MotionLayout peut animer tout ce qui fournit un setter sur n'importe quelle vue.
Essayer
- Exécutez à nouveau l'application et passez à l'étape 6 pour voir l'animation en action. Lorsque vous cliquez sur la lune, elle suit son trajet du début à la fin, en passant par chaque
KeyAttributespécifié dans lesKeyFrameSet.

Lorsque vous ajoutez d'autres KeyFrames, MotionLayout modifie la trajectoire de la Lune en la faisant passer d'une ligne droite à une courbe complexe, ce qui ajoute un double saut périlleux arrière, un redimensionnement et un changement de couleur au milieu de l'animation.
Dans les animations réelles, vous animez souvent plusieurs vues en même temps en contrôlant leur mouvement le long de différents chemins et à différentes vitesses. En spécifiant un KeyFrame différent pour chaque vue, il est possible de créer une chorégraphie d'animations riches qui animent plusieurs vues avec MotionLayout.
10. Événements de déplacement et chemins complexes
Au cours de cette étape, vous allez apprendre à utiliser OnSwipe avec des chemins d'accès complexes. Jusqu'à présent, l'animation de la Lune a été déclenchée par un écouteur OnClick et dure une durée fixe.
Pour contrôler des animations dont les tracés sont complexes à l'aide de OnSwipe, comme l'animation lunaire que vous avez créée au cours des dernières étapes, vous devez comprendre le fonctionnement de OnSwipe.
Étape 1: Explorez le comportement d'OnSwipe
- Ouvrez
xml/step7.xmlet recherchez la déclarationOnSwipeexistante.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
/>
- Exécutez l'application sur votre appareil et passez à l'étape 7. Essayez de produire une animation fluide en faisant glisser la lune le long de la trajectoire de l'arc.
Cette animation n'est pas très satisfaisante lorsque vous l'exécutez. Lorsque la Lune atteint le sommet de l'arc, elle commence à sauter.

Pour comprendre le bug, réfléchissez à ce qui se passe lorsque l'utilisateur appuie juste en dessous de la partie supérieure de l'arc. Comme la balise OnSwipe comporte un élément motion:touchAnchorSide="bottom", MotionLayout tentera de maintenir la distance entre le doigt et le bas de la vue constant tout au long de l'animation.
Cependant, comme le bas de la Lune ne va pas toujours dans la même direction, il monte, puis revient vers le bas. MotionLayout ne sait donc pas quoi faire lorsque l'utilisateur vient de passer le haut de l'arc. Sachant cela, puisque vous suivez le bas de la Lune, où doit-il être placé lorsque l'utilisateur touche ici ?

Étape 2: Utilisez le côté droit
Pour éviter ce type de bug, il est important de toujours choisir une touchAnchorId et une touchAnchorSide qui progressent toujours dans une direction pendant toute la durée de l'animation.
Dans cette animation, les côtés right et left de la Lune progresseront tous deux à l'écran dans une direction.
Cependant, bottom et top vont s'inverser. Lorsque OnSwipe tente de le suivre, il est confus quand sa direction change.
- Pour que cette animation suive les événements tactiles, définissez
touchAnchorSidesurright.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="right"
/>
Étape 3: Utilisez dragDirection
Vous pouvez également combiner dragDirection et touchAnchorSide pour modifier la direction d'un rail latéral. Il est toujours important que touchAnchorSide progresse dans une seule direction, mais vous pouvez indiquer à MotionLayout dans quelle direction effectuer le suivi. Par exemple, vous pouvez conserver touchAnchorSide="bottom", mais ajouter dragDirection="dragRight". MotionLayout suivra la position du bas de la vue, mais ne tiendra compte de sa position que lorsqu'il se déplacera vers la droite (les mouvements verticaux seront ignorés). Ainsi, même si la partie inférieure monte et descend, l'animation s'effectue toujours correctement avec OnSwipe.
- Mettez à jour
OnSwipepour suivre correctement le mouvement de la Lune.
step7.xml
<!-- Using dragDirection to control the direction of drag tracking →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragRight"
/>
Essayer
- Exécutez à nouveau l'application et essayez de faire glisser la lune le long du tracé. Même s'il suit un arc complexe,
MotionLayoutpeut faire progresser l'animation en réponse aux événements de balayage.

11. Mouvement en cours avec du code
MotionLayout permet de créer des animations enrichies avec CoordinatorLayout. Au cours de cette étape, vous allez créer un en-tête réductible à l'aide de MotionLayout.
Étape 1: Explorez le code existant
- Pour commencer, ouvrez
layout/activity_step8.xml. - Dans
layout/activity_step8.xml, vous constatez qu'unCoordinatorLayoutet unAppBarLayoutfonctionnels sont déjà créés.
activity_step8.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="180dp">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
... >
...
</androidx.constraintlayout.motion.widget.MotionLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
...
motion:layout_behavior="@string/appbar_scrolling_view_behavior" >
...
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Cette mise en page utilise un CoordinatorLayout pour partager des informations de défilement entre NestedScrollView et AppBarLayout. Ainsi, lorsque NestedScrollView défile vers le haut, il informe AppBarLayout du changement. C'est ainsi que vous implémentez une barre d'outils qui peut être réduite comme celle-ci sur Android : le défilement du texte sera "coordonné". avec l'en-tête escamotable.
La scène de mouvement vers laquelle pointe @id/motion_layout est semblable à la scène de mouvement de la dernière étape. Cependant, la déclaration OnSwipe a été supprimée pour lui permettre de fonctionner avec CoordinatorLayout.
- Exécutez l'application et passez à l'étape 8. Vous voyez que lorsque vous faites défiler le texte, la lune ne bouge pas.
Étape 2: Faire défiler MotionLayout
- Pour faire défiler la vue
MotionLayoutdès queNestedScrollViewdéfile, ajoutezmotion:minHeightetmotion:layout_scrollFlagsàMotionLayout.
activity_step8.xml
<!-- Add minHeight and layout_scrollFlags to the MotionLayout -->
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layoutDescription="@xml/step8"
motion:motionDebug="SHOW_PATH"
android:minHeight="80dp"
motion:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed" >
- Exécutez à nouveau l'application et passez à l'étape 8. Vous constatez que
MotionLayoutse réduit lorsque vous faites défiler la page vers le haut. Toutefois, l'animation ne progresse pas encore en fonction du comportement de défilement.
Étape 3: Déplacez le mouvement avec du code
- Ouvrez
Step8Activity.kt. Modifiez la fonctioncoordinateMotion()pour indiquer àMotionLayoutles changements de position de défilement.
Step8Activity.kt
// TODO: set progress of MotionLayout based on an AppBarLayout.OnOffsetChangedListener
private fun coordinateMotion() {
val appBarLayout: AppBarLayout = findViewById(R.id.appbar_layout)
val motionLayout: MotionLayout = findViewById(R.id.motion_layout)
val listener = AppBarLayout.OnOffsetChangedListener { unused, verticalOffset ->
val seekPosition = -verticalOffset / appBarLayout.totalScrollRange.toFloat()
motionLayout.progress = seekPosition
}
appBarLayout.addOnOffsetChangedListener(listener)
}
Ce code enregistre un OnOffsetChangedListener qui sera appelé chaque fois que l'utilisateur fait défiler la page avec le décalage de défilement actuel.
MotionLayout permet de rechercher sa transition en définissant la propriété de progression. Pour convertir une valeur verticalOffset en pourcentage de progression, divisez-la par la plage de défilement totale.
Essayer
- Déployez à nouveau l'application et exécutez l'animation de l'étape 8.
MotionLayoutfait progresser l'animation en fonction de la position de défilement.

Il est possible de créer des animations personnalisées pour la barre d'outils de réduction dynamique à l'aide de MotionLayout. En utilisant une séquence de KeyFrames, vous pouvez obtenir des effets très audacieux.
12. Félicitations
Cet atelier de programmation a couvert l'API de base de MotionLayout.
Pour voir d'autres exemples pratiques de MotionLayout, consultez l'exemple officiel. N'oubliez pas de consulter la documentation.
En savoir plus
MotionLayout prend en charge encore plus de fonctionnalités qui ne sont pas abordées dans cet atelier de programmation, comme KeyCycle,, qui vous permet de contrôler les chemins ou les attributs avec des cycles répétés, et KeyTimeCycle,, qui vous permet d'animer des événements en fonction de l'heure. Consultez les exemples pour chaque méthode.
Pour obtenir des liens vers d'autres ateliers de ce cours, consultez la page de destination des ateliers de programmation avancés pour Android en Kotlin.