Mengelola animasi gerakan dan widget dengan MotionLayout

Mencoba cara Compose
Jetpack Compose adalah toolkit UI yang direkomendasikan untuk Android. Pelajari cara menggunakan animasi di Compose.

MotionLayout adalah jenis tata letak yang membantu Anda mengelola animasi gerakan dan widget di aplikasi Anda. MotionLayout adalah subclass dari ConstraintLayout dan dibuat berdasarkan kemampuan tata letaknya yang kaya. Sebagai bagian dari library ConstraintLayout, MotionLayout tersedia sebagai support library.

MotionLayout menghubungkan celah antara penanganan gerakan yang kompleks dan transisi tata letak, yang menawarkan perpaduan fitur antara framework animasi properti, TransitionManager, dan CoordinatorLayout.

Gambar 1. Gerakan dasar yang dikontrol sentuhan.

Selain menjelaskan transisi antara tata letak, MotionLayout juga memungkinkan Anda menganimasikan properti tata letak apa pun. Selain itu, kode tersebut pada dasarnya mendukung transisi yang dapat dicari. Artinya, Anda dapat langsung menampilkan titik apa pun dalam transisi berdasarkan beberapa ketentuan, seperti input sentuhan. MotionLayout juga mendukung bingkai utama, sehingga memungkinkan transisi yang sepenuhnya disesuaikan agar sesuai dengan kebutuhan Anda.

MotionLayout sepenuhnya bersifat deklaratif, artinya Anda dapat menjelaskan transisi apa pun dalam XML, terlepas dari seberapa besar kompleksitasnya.

Pertimbangan desain

MotionLayout ditujukan untuk memindahkan, mengubah ukuran, dan menganimasikan elemen UI yang digunakan pengguna untuk berinteraksi, seperti tombol dan baris judul. Jangan gunakan gerakan di aplikasi Anda sebagai efek khusus tanpa alasan. Gunakan untuk membantu pengguna memahami hal yang dilakukan aplikasi Anda. Untuk mengetahui informasi selengkapnya tentang cara mendesain aplikasi dengan gerakan, lihat bagian Desain Material Memahami gerakan.

Mulai

Ikuti langkah-langkah ini untuk mulai menggunakan MotionLayout di project Anda.

  1. Tambahkan dependensi ConstraintLayout: Untuk menggunakan MotionLayout di project Anda, tambahkan dependensi ConstraintLayout 2.0 ke file build.gradle aplikasi Anda. Jika Anda menggunakan AndroidX, tambahkan dependensi berikut:

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.1"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1"
    }

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.1")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1")
    }
  2. Membuat file MotionLayout: MotionLayout adalah subclass dari ConstraintLayout, sehingga Anda dapat mengubah ConstraintLayout apa pun yang ada menjadi MotionLayout dengan mengganti nama class di file resource tata letak Anda, seperti yang ditunjukkan dalam contoh berikut:

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    Support library

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    Berikut adalah contoh lengkap file MotionLayout, yang menentukan tata letak yang ditampilkan pada gambar 1:

    AndroidX

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    Support library

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  3. Membuat MotionScene: dalam contoh MotionLayout sebelumnya, atribut app:layoutDescription mereferensikan adegan gerakan. Scene gerak adalah file resource XML. Dalam elemen <MotionScene> root-nya, adegan gerakan berisi semua deskripsi gerakan untuk tata letak yang sesuai. Agar informasi tata letak terpisah dari deskripsi gerakan, setiap MotionLayout mereferensikan adegan gerakan yang terpisah. Definisi dalam adegan gerakan lebih diutamakan daripada definisi apa pun yang serupa dalam MotionLayout.

    Berikut contoh file scene gerak yang menjelaskan gerakan horizontal dasar pada gambar 1:

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    Perhatikan hal berikut:

    • <Transition> berisi definisi dasar gerakan.

      • motion:constraintSetStart dan motion:constraintSetEnd adalah referensi ke endpoint gerakan. Endpoint ini ditentukan dalam elemen <ConstraintSet> di adegan gerakan.

      • motion:duration menentukan jumlah milidetik yang diperlukan untuk menyelesaikan gerakan.

    • <OnSwipe> memungkinkan Anda membuat kontrol sentuh untuk gerakan.

      • motion:touchAnchorId merujuk pada tampilan yang dapat digeser dan ditarik pengguna.

      • motion:touchAnchorSide berarti tampilan sedang ditarik dari sisi kanan.

      • motion:dragDirection merujuk pada arah progres penarikan tampilan. Misalnya, motion:dragDirection="dragRight" berarti progres meningkat saat tampilan ditarik ke kanan.

    • <ConstraintSet> adalah tempat Anda menentukan berbagai batasan yang menjelaskan gerakan Anda. Dalam contoh ini, satu <ConstraintSet> ditentukan untuk setiap endpoint gerakan Anda. Endpoint ini dipindahkan ke tengah secara vertikal menggunakan app:layout_constraintTop_toTopOf="parent" dan app:layout_constraintBottom_toBottomOf="parent". Secara horizontal, endpoint tersebut berada di ujung sisi kiri dan kanan layar.

    Untuk mengetahui tampilan yang lebih detail pada berbagai elemen yang didukung adegan gerakan, lihat contoh MotionLayout.

Atribut yang diinterpolasi

Dalam file scene gerak, elemen ConstraintSet dapat berisi atribut tambahan yang diinterpolasi selama transisi. Selain posisi dan batas, atribut berikut diinterpolasi oleh MotionLayout:

  • alpha
  • visibility
  • elevation
  • rotation, rotationX, rotationY
  • translationX, translationY, translationZ
  • scaleX, scaleY

Atribut khusus

Dalam <Constraint>, Anda dapat menggunakan elemen <CustomAttribute> untuk menentukan transisi atribut yang tidak hanya terkait dengan atribut View atau posisi.

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

Satu <CustomAttribute> berisi dua atributnya sendiri:

  • motion:attributeName diperlukan dan harus cocok dengan objek menggunakan metode penyetel dan pengambil. Getter dan setter harus cocok dengan pola tertentu. Misalnya, backgroundColor didukung, karena tampilan memiliki metode getBackgroundColor() dan setBackgroundColor() yang mendasarinya.
  • Atribut lain yang harus Anda berikan didasarkan pada jenis nilai. Pilih dari jenis yang didukung berikut:
    • motion:customColorValue untuk warna
    • motion:customIntegerValue untuk bilangan bulat
    • motion:customFloatValue untuk float
    • motion:customStringValue untuk string
    • motion:customDimension untuk dimensi
    • motion:customBoolean untuk boolean

Saat menentukan atribut kustom, tentukan nilai endpoint di elemen <ConstraintSet> awal dan akhir.

Mengubah warna latar belakang

Berdasarkan contoh sebelumnya, misalkan Anda ingin warna tampilan berubah sebagai bagian dari gerakannya, seperti yang ditunjukkan pada gambar 2.

Gambar 2. Tampilan mengubah warna latar belakangnya saat bergerak.

Tambahkan elemen <CustomAttribute> untuk setiap elemen ConstraintSet, seperti yang ditunjukkan dalam cuplikan kode berikut:

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

Atribut MotionLayout tambahan

Selain atribut dalam contoh sebelumnya, MotionLayout memiliki atribut lain yang mungkin ingin Anda tentukan:

  • app:applyMotionScene="boolean" menunjukkan apakah akan menerapkan adegan gerak atau tidak. Nilai default untuk atribut ini adalah true.
  • app:showPaths="boolean" menunjukkan apakah akan menampilkan jalur gerak saat gerakan sedang berjalan. Nilai default untuk atribut ini adalah false.
  • app:progress="float" memungkinkan Anda menentukan progres transisi secara eksplisit. Anda dapat menggunakan nilai floating point dari 0 (awal transisi) hingga 1 (akhir transisi).
  • app:currentState="reference" memungkinkan Anda menentukan ConstraintSet tertentu.
  • app:motionDebug memungkinkan Anda menampilkan informasi debug tambahan tentang gerakan. Nilai yang mungkin adalah "SHOW_PROGRESS", "SHOW_PATH", atau "SHOW_ALL".

Referensi lainnya

Untuk mengetahui informasi selengkapnya tentang MotionLayout, lihat referensi berikut: