Karussell mit MotionLayout

Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Hinzufügen eines Karussells in Compose

Carousel ist ein Objekt, das die Bewegung unterstützt und mit dem benutzerdefinierte Karussellansichten erstellt werden können, in denen eine Liste von Elementen angezeigt wird, die der Nutzer durchblättern kann. Im Vergleich zu anderen Methoden zum Implementieren solcher Ansichten können Sie mit diesem Helfer schnell komplexe Bewegungs- und Dimensionsänderungen für Ihre Carousel erstellen, indem Sie MotionLayout nutzen.

Das Carousel-Widget unterstützt Listen mit einem Start und einem Ende sowie zirkuläre Listen.

So funktioniert das Karussell mit MotionLayout

Angenommen, Sie möchten eine horizontale Carousel-Ansicht erstellen, in der das mittlere Element vergrößert wird:

Dieses grundlegende Layout enthält mehrere Ansichten, die die Carousel-Elemente darstellen:

Erstellen Sie ein MotionLayout mit den folgenden drei Status und weisen Sie ihnen IDs zu:

  • Vorherige
  • start
  • Weiter

Wenn der Status start dem Basis-Layout entspricht, werden die Carousel-Elemente im Status previous und im Status next jeweils um eins nach links und rechts verschoben.

Nehmen wir als Beispiel die fünf Ansichten in Abbildung 3. Im Startzustand sind die Ansichten B, C und D sichtbar, während A und E außerhalb des Bildschirms liegen. Richten Sie den vorherigen Zustand so ein, dass sich die Positionen von A, B, C und D dort befinden, wo sich B, C, D und E befanden, wobei sich die Ansichten von links nach rechts bewegen. Im nächsten Zustand muss das Gegenteil passieren: B, C, D und E müssen an die Positionen von A, B, C und D verschoben werden und die Ansichten müssen sich von rechts nach links bewegen. Dies ist in Abbildung 4 dargestellt:

Es ist wichtig, dass die Ansichten genau dort enden, wo die ursprünglichen Ansichten beginnen. Carousel erweckt den Eindruck einer unendlichen Sammlung von Elementen, indem die tatsächlichen Ansichten an ihren ursprünglichen Ort zurückgesetzt und mit den neuen passenden Inhalten neu initialisiert werden. Das folgende Diagramm veranschaulicht diesen Mechanismus. Achten Sie auf die Werte für „item #“:

Übergänge

Nachdem Sie diese drei Einschränkungssätze in Ihrer Motion-Scene-Datei definiert haben, erstellen Sie zwei Übergänge – vorwärts und rückwärts – zwischen den Status start und next sowie zwischen den Status start und previous. Fügen Sie einen OnSwipe-Handler hinzu, um die Übergänge als Reaktion auf eine Geste auszulösen, wie im folgenden Beispiel gezeigt:

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

Nachdem diese grundlegende Bewegungsszene erstellt wurde, fügen Sie dem Layout einen Carousel-Helfer hinzu und verweisen Sie auf die Ansichten in derselben Reihenfolge, in der Sie die vorherige und nächste Animation implementieren.

Legen Sie die folgenden Attribute für den Carousel-Helper fest:

  • app:carousel_firstView: die Ansicht, die das erste Element des Carousel darstellt, in diesem Beispiel C.
  • app:carousel_previousState: die ConstraintSet-ID des vorherigen Status.
  • app:carousel_nextState: Die ConstraintSet-ID des nächsten Status.
  • app:carousel_backwardTransition: die Transition-ID, die zwischen dem Start- und dem vorherigen-Status angewendet wurde.
  • app:carousel_forwardTransition: Die Transition-ID, die zwischen den Status start und next angewendet wird.

Ihre XML-Layoutdatei könnte beispielsweise so aussehen:

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

Carousel-Adapter im Code einrichten:

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

Zusätzliche Anmerkungen

Je nachdem, welches Element in der Carousel gerade ausgewählt ist, müssen die Ansichten, die die vorherigen oder nachfolgenden Elemente darstellen, möglicherweise ausgeblendet werden, um die Carousel start und end richtig zu berücksichtigen. Der Carousel-Helfer übernimmt das automatisch. Standardmäßig werden diese Ansichten in diesen Situationen als View.INVISIBLE markiert, sodass sich das Gesamtdesign nicht ändert.

Es ist ein alternativer Modus verfügbar, in dem der Carousel-Helfer diese Ansichten stattdessen als View.GONE markiert. Sie können diesen Modus mit der folgenden Property festlegen:

app:carousel_emptyViewsBehavior="gone"

Beispiele

Weitere Beispiele für die Verwendung des Carousel-Helpers finden Sie in den Beispielprojekten auf GitHub.