Carrousel avec MotionLayout

Carousel est un objet d'aide au mouvement qui permet de créer des vues de carrousel personnalisées qui affichent une liste d'éléments que l'utilisateur peut parcourir. Comparé à d'autres méthodes d'implémentation de ces vues, cet outil d'aide vous permet de créer rapidement des modifications complexes de mouvement et de dimension pour votre Carousel à l'aide de MotionLayout.

Le widget Carousel accepte les listes avec un début et une fin, ainsi que des listes de retour à la ligne circulaires.

Fonctionnement de Carousel avec MotionLayout

Supposons que vous souhaitiez créer une vue Carousel horizontale, avec agrandissement de l'élément central:

Cette mise en page de base contient plusieurs vues représentant les éléments Carousel:

Créez une MotionLayout avec les trois états suivants et attribuez-leur des ID:

  • précédent
  • démarrer
  • Suivant

Si l'état start correspond à la mise en page de base, à l'état previous (précédent) et à l'état next (suivant), les éléments Carousel sont décalés de 1 vers la gauche et vers la droite, respectivement.

Prenons l'exemple des cinq vues de la figure 3 et supposons qu'à l'état start, les vues B, C et D sont visibles, et A et E en dehors de l'écran. Configurez l'état précédent de sorte que les positions A, B, C et D correspondent à celles de B, C, D et E, et que les vues se déplacent de gauche à droite. À l'état prochain, l'inverse doit se produire. B, C, D et E se déplacent à l'endroit A, B, C et D, et les vues se déplacent de droite à gauche. Ce processus est illustré dans la figure 4:

Il est essentiel que les vues se retrouvent exactement là où commence les vues d'origine. Carousel donne l'illusion d'une collection infinie d'éléments en déplaçant les vues réelles là où elles se trouvaient, mais en les réinitialisant avec le nouveau contenu correspondant. Le schéma suivant illustre ce mécanisme. Faites attention aux valeurs de l'attribut "item #" [numéro d'article]):

Transitions

Une fois ces trois ensembles de contraintes définis dans votre fichier de scène de mouvement, créez deux transitions (avant et arrière) entre les états start et next et les états start et previous. Ajoutez un gestionnaire OnSwipe pour déclencher les transitions en réponse à un geste, comme illustré dans l'exemple suivant:

    <Transition
        motion:constraintSetStart="@id/start"
        motion:constraintSetEnd="@+id/next"
        motion:duration="1000"
        android:id="@+id/forward">
        <OnSwipe
            motion:dragDirection="dragLeft"
            motion:touchAnchorSide="left" />
    </Transition>

    <Transition
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/previous"
        android:id="@+id/backward">
        <OnSwipe
            motion:dragDirection="dragRight"
            motion:touchAnchorSide="right" />
    </Transition>

Une fois cette scène de mouvement de base créée, ajoutez un assistant Carousel à la mise en page et référencez les vues dans l'ordre dans lequel vous implémentez votre animation précédente et suivante.

Définissez les attributs suivants pour l'outil d'aide Carousel:

  • app:carousel_firstView: vue qui représente le premier élément de Carousel (dans cet exemple, C).
  • app:carousel_previousState: ID ConstraintSet de l'état précédent.
  • app:carousel_nextState: ID ConstraintSet de l'état prochain.
  • app:carousel_backwardTransition: ID Transition appliqué entre les états début et précédent.
  • app:carousel_forwardTransition: ID Transition appliqué entre les états start et next.

Par exemple, votre fichier XML de mise en page doit ressembler à ceci:

    <androidx.constraintlayout.motion.widget.MotionLayout ... >

        <ImageView  android:id="@+id/imageView0" .. />
        <ImageView  android:id="@+id/imageView1" .. />
        <ImageView  android:id="@+id/imageView2" .. />
        <ImageView  android:id="@+id/imageView3" .. />
        <ImageView  android:id="@+id/imageView4" .. />

        <androidx.constraintlayout.helper.widget.Carousel
            android:id="@+id/carousel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:carousel_forwardTransition="@+id/forward"
            app:carousel_backwardTransition="@+id/backward"
            app:carousel_previousState="@+id/previous"
            app:carousel_nextState="@+id/next"
            app:carousel_infinite="true"
            app:carousel_firstView="@+id/imageView2"
            app:constraint_referenced_ids="imageView0,imageView1,imageView2,imageView3,imageView4" />

    </androidx.constraintlayout.motion.widget.MotionLayout>

Configurez un adaptateur Carousel dans le code:

Kotlin

carousel.setAdapter(object : Carousel.Adapter {
            override fun count(): Int {
              // Return the number of items in the Carousel.
            }

            override fun populate(view: View, index: Int) {
                // Implement this to populate the view at the given index.
            }

            override fun onNewItem(index: Int) {
                // Called when an item is set.
            }
        })

Java

carousel.setAdapter(new Carousel.Adapter() {
            @Override
            public int count() {
                // Return the number of items in the Carousel.
            }

            @Override
            public void populate(View view, int index) {
                // Populate the view at the given index.
            }

            @Override
            public void onNewItem(int index) {
                 // Called when an item is set.
            }
        });

Remarques supplémentaires

En fonction de l'élément actuel "sélectionné" dans le Carousel, les vues représentant les éléments avant ou après devront peut-être être masquées pour prendre correctement en compte le début et la fin de Carousel. L'outil d'aide Carousel gère cela automatiquement. Par défaut, il marque ces vues comme View.INVISIBLE dans ces situations, de sorte que la mise en page globale ne change pas.

Un autre mode est disponible dans lequel l'outil d'aide Carousel marque ces vues comme View.GONE. Vous pouvez définir ce mode à l'aide de la propriété suivante:

app:carousel_emptyViewsBehavior="gone"

Exemples

Pour plus d'exemples d'utilisation de l'outil d'aide du carrousel, consultez les exemples de projets sur GitHub.