Carosello con MotionLayout

Carousel è un oggetto helper di movimento per creare visualizzazioni di carosello personalizzate che mostrano un elenco di elementi che l'utente può scorrere. Rispetto ad altri modi per implementare queste viste, questo aiuto ti consente di creare rapidamente modifiche complesse di movimento e dimensione per il tuo Carousel sfruttando MotionLayout.

Il widget Carousel supporta elenchi con inizio e fine e elenchi circolari a tutto tondo.

Come funziona Carousel con MotionLayout

Supponi di voler creare una visualizzazione Carousel orizzontale, con l'elemento centrale ingrandito:

Questo layout di base contiene diverse visualizzazioni che rappresentano Carousel elementi:

Crea un MotionLayout con i tre stati seguenti e fornisci gli ID:

  • precedente
  • avvia
  • Avanti

Se lo stato start corrisponde al layout di base, nello stato precedente e successivo gli elementi Carousel vengono spostati di uno a sinistra e a destra, rispettivamente.

Ad esempio, prendi le cinque viste nella figura 3 e supponiamo che, nello stato start, le viste B, C e D siano visibili, mentre A ed E sono esterne allo schermo. Imposta lo stato precedente in modo che le posizioni di A, B, C e D si trovino dove B, C, D ed E, con le viste che si spostano da sinistra a destra. Nello stato successivo, deve verificarsi il contrario, in cui B, C, D ed E si spostano nei punti in cui si trovavano A, B, C e D e le viste si spostano da destra a sinistra. Questo è quanto mostrato nella Figura 4:

È fondamentale che le visualizzazioni finiscano esattamente nel punto in cui iniziano le visualizzazioni originali. Carousel dà l'illusione di una raccolta infinita di elementi spostando le visualizzazioni effettive nella posizione in cui si trovavano, ma reinizializzandole con i nuovi contenuti corrispondenti. Il seguente diagramma mostra questo meccanismo. Presta attenzione ai valori "articolo n."):

Transizioni

Con questi tre insiemi di vincoli definiti nel file della scena di animazione, crea due transizioni, avanti e indietro, tra gli stati start e next e gli stati start e previous. Aggiungi un gestore OnSwipe per attivare le transizioni in risposta a un gesto, come mostrato nell'esempio seguente:

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

Dopo aver creato questa scena di movimento di base, aggiungi un helper Carousel al layout e fai riferimento alle viste nello stesso ordine in cui implementi l'animazione precedente e successiva.

Imposta i seguenti attributi per l'helper Carousel:

  • app:carousel_firstView: la vista che rappresenta il primo elemento dell'elemento Carousel, in questo esempio C.
  • app:carousel_previousState: l'ID ConstraintSet dello stato precedente.
  • app:carousel_nextState: l'ID ConstraintSet dello stato successivo.
  • app:carousel_backwardTransition: l'ID Transition applicato tra gli stati inizio e precedente.
  • app:carousel_forwardTransition: l'ID Transition applicato tra gli stati start e next.

Ad esempio, il tuo file XML di layout contiene un aspetto simile al seguente:

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

Configura un adattatore Carousel nel codice:

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.
            }
        });

Note aggiuntive

A seconda dell'elemento corrente "selezionato" in Carousel, le visualizzazioni che rappresentano gli elementi prima o dopo potrebbero dover essere nascoste per tenere correttamente conto di inizio e fine di Carousel. L'helper Carousel gestisce questa operazione automaticamente. Per impostazione predefinita, queste visualizzazioni vengono contrassegnate come View.INVISIBLE in queste situazioni, perciò il layout generale non cambia.

È disponibile una modalità alternativa in cui l'helper Carousel contrassegna invece le viste come View.GONE. Puoi impostare questa modalità utilizzando la seguente proprietà:

app:carousel_emptyViewsBehavior="gone"

Esempi

Per altri esempi sull'utilizzo dell'helper Carosello, vedi i progetti di esempio su GitHub.