Carrusel con MotionLayout

Prueba hacerlo con Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Obtén más información para agregar un carrusel en Compose.

Carousel es un objeto de ayuda de movimiento para compilar vistas de carrusel personalizadas que muestran una lista de elementos que el usuario puede revisar rápidamente. En comparación con otras formas de implementar esas vistas, este asistente te permite crear rápidamente cambios complejos de movimiento y dimensión para tu Carousel aprovechando MotionLayout.

El widget Carousel admite listas con un inicio y un final, así como listas circulares.

Cómo funciona el carrusel con MotionLayout

Supongamos que deseas crear una vista de Carousel horizontal con el elemento central ampliado:

Este diseño básico contiene varias vistas que representan los elementos de Carousel:

Crea un MotionLayout con los siguientes tres estados y asígnale IDs:

  • Anterior
  • iniciar
  • siguiente

Si el estado start corresponde al diseño base, en el estado previous y en el estado next, los elementos Carousel se desplazan uno a la izquierda y uno a la derecha, respectivamente.

Por ejemplo, toma las cinco vistas de la figura 3 y supón que, en el estado inicial, las vistas B, C y D son visibles, y A y E están fuera de la pantalla. Configura el estado anterior de modo que las posiciones de A, B, C y D sean las mismas que las de B, C, D y E, con las vistas moviéndose de izquierda a derecha. En el estado siguiente, debe ocurrir lo contrario: B, C, D y E se mueven a donde estaban A, B, C y D, y las vistas se mueven de derecha a izquierda. Esto se muestra en la figura 4:

Es fundamental que las vistas terminen exactamente donde comienzan las vistas originales. Carousel da la ilusión de una colección infinita de elementos moviendo las vistas reales de vuelta a donde estaban, pero reinicializándolas con el nuevo contenido coincidente. En el siguiente diagrama, se muestra este mecanismo. Presta atención a los valores de "número de artículo"):

Transiciones

Con estos tres conjuntos de restricciones definidos en tu archivo de escena de movimiento, crea dos transiciones (hacia adelante y hacia atrás) entre los estados start y next, y los estados start y previous. Agrega un controlador OnSwipe para activar las transiciones en respuesta a un gesto, como se muestra en el siguiente ejemplo:

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

Después de crear esta escena de movimiento básica, agrega un asistente Carousel al diseño y haz referencia a las vistas en el mismo orden en que implementas tu animación anterior y siguiente.

Establece los siguientes atributos para el asistente Carousel:

  • app:carousel_firstView: Es la vista que representa el primer elemento de Carousel; en este ejemplo, C.
  • app:carousel_previousState: Es el ID de ConstraintSet del estado anterior.
  • app:carousel_nextState: Es el ID de ConstraintSet del estado siguiente.
  • app:carousel_backwardTransition: Es el ID de Transition que se aplica entre los estados start y previous.
  • app:carousel_forwardTransition: Es el ID de Transition aplicado entre los estados start y next.

Por ejemplo, puedes tener algo como lo siguiente en tu archivo XML de diseño:

    <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 adaptador Carousel en el código:

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

Notas adicionales

Según el elemento actual "seleccionado" en Carousel, es posible que las vistas que representan los elementos anteriores o posteriores deban ocultarse para tener en cuenta correctamente el inicio y el final de Carousel. El asistente Carousel controla esto automáticamente. De forma predeterminada, en estas situaciones, marca esas vistas como View.INVISIBLE, por lo que no cambia el diseño general.

Hay un modo alternativo disponible en el que el asistente Carousel marca esas vistas como View.GONE. Puedes configurar este modo con la siguiente propiedad:

app:carousel_emptyViewsBehavior="gone"

Ejemplos

Para obtener más ejemplos sobre el uso del asistente de carrusel, consulta los proyectos de ejemplo en GitHub.