1. Sebelum memulai
Codelab ini adalah bagian dari kursus Android Lanjutan di Kotlin. Anda akan mendapatkan manfaat maksimal dari kursus ini jika menyelesaikan codelab secara berurutan, tetapi ini tidak bersifat wajib. Semua codelab kursus tercantum di halaman landing codelab Android Lanjutan di Kotlin.
MotionLayout adalah library yang memungkinkan Anda menambahkan gerakan yang kaya ke dalam aplikasi Android Anda. Library ini didasarkan pada ConstraintLayout, dan memungkinkan Anda menganimasikan apa pun yang dapat Anda buat menggunakan ConstraintLayout.
Anda dapat menggunakan MotionLayout untuk menganimasikan lokasi, ukuran, visibilitas, alfa, warna, ketinggian, rotasi, dan atribut lainnya dari beberapa tampilan sekaligus. Dengan menggunakan XML deklaratif, Anda dapat membuat animasi terkoordinasi yang melibatkan beberapa tampilan yang sulit dicapai dalam kode.
Animasi adalah cara yang bagus untuk meningkatkan pengalaman aplikasi. Anda dapat menggunakan animasi untuk:
- Tampilkan perubahan—menganimasikan antara status memungkinkan pengguna secara alami melacak perubahan di UI Anda.
- Menarik perhatian—gunakan animasi untuk menarik perhatian ke elemen UI yang penting.
- Buat desain yang menarik—gerakan yang efektif dalam desain membuat aplikasi terlihat sempurna.
Prasyarat
Codelab ini dirancang untuk developer dengan beberapa pengalaman pengembangan Android. Sebelum mencoba menyelesaikan codelab ini, Anda harus:
- Mengetahui cara membuat aplikasi dengan aktivitas, tata letak dasar, dan menjalankannya di perangkat atau emulator menggunakan Android Studio. Pahami
ConstraintLayout. Baca codelab Constraint Layout untuk mempelajariConstraintLayoutlebih lanjut.
Yang akan Anda lakukan
- Menentukan animasi dengan
ConstraintSetsdanMotionLayout - Membuat animasi berdasarkan peristiwa tarik
- Mengubah animasi dengan
KeyPosition - Mengubah atribut dengan
KeyAttribute - Menjalankan animasi dengan kode
- Menganimasikan header yang dapat diciutkan dengan
MotionLayout
Yang Anda butuhkan
- Android Studio 4.0 (Editor
MotionLayouthanya berfungsi dengan Android Studio versi ini.)
2. Memulai
Untuk mendownload aplikasi contoh, Anda dapat melakukan:
... atau clone repositori GitHub dari command line dengan menggunakan perintah berikut:
$ git clone https://github.com/googlecodelabs/motionlayout.git
3. Membuat animasi dengan MotionLayout
Pertama, Anda akan membuat animasi yang memindahkan tampilan dari awal atas layar ke akhir bawah sebagai respons terhadap klik pengguna.
Untuk membuat animasi dari kode awal, Anda memerlukan bagian utama berikut:
MotionLayout,yang merupakan subclass dariConstraintLayout. Anda menentukan semua tampilan yang akan dianimasikan di dalam tagMotionLayout.MotionScene,yang merupakan file XML yang menjelaskan animasi untukMotionLayout.Transition,yang merupakan bagian dariMotionSceneyang menentukan durasi animasi, pemicu, dan cara memindahkan tampilan.ConstraintSetyang menentukan batasan start dan end transisi.
Mari kita lihat satu per satu, dimulai dengan MotionLayout.
Langkah 1: Pelajari kode yang ada
MotionLayout adalah subclass dari ConstraintLayout, sehingga mendukung semua fitur yang sama sambil menambahkan animasi. Untuk menggunakan MotionLayout, Anda menambahkan tampilan MotionLayout di tempat Anda akan menggunakan ConstraintLayout.
- Di
res/layout, bukaactivity_step1.xml.Di sini Anda memilikiConstraintLayoutdengan satuImageViewbintang, dengan warna yang diterapkan di dalamnya.
activity_step1.xml
<!-- initial code -->
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/red_star"
...
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
ConstraintLayout ini tidak memiliki batasan apa pun, jadi jika Anda menjalankan aplikasi sekarang, Anda akan melihat tampilan bintang tanpa batasan, yang berarti bintang akan diposisikan di lokasi yang tidak diketahui. Android Studio akan memberikan peringatan tentang kurangnya batasan.
Langkah 2: Konversi ke Tata Letak Gerakan
Untuk menganimasikan menggunakan MotionLayout,, Anda harus mengonversi ConstraintLayout menjadi MotionLayout.
Agar tata letak Anda dapat menggunakan adegan gerakan, tata letak harus menunjuk ke adegan tersebut.
- Untuk melakukannya, buka permukaan desain. Di Android Studio 4.0, Anda membuka permukaan desain menggunakan ikon terpisah atau desain di kanan atas saat melihat file XML tata letak.

- Setelah Anda membuka permukaan desain, klik kanan pratinjau, lalu pilih Convert to MotionLayout.

Tindakan ini menggantikan tag ConstraintLayout dengan tag MotionLayout dan menambahkan motion:layoutDescription ke tag MotionLayout yang mengarah ke @xml/activity_step1_scene.
activity_step1**.xml**
<!-- explore motion:layoutDescription="@xml/activity_step1_scene" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/activity_step1_scene">
Scene gerak adalah satu file XML yang mendeskripsikan animasi dalam MotionLayout.
Segera setelah Anda mengonversi ke MotionLayout, platform desain akan menampilkan Motion Editor

Ada tiga elemen UI baru di Motion Editor:
- Ringkasan – Ini adalah pilihan modal yang memungkinkan Anda memilih berbagai bagian animasi. Dalam gambar ini,
startConstraintSetdipilih. Anda juga dapat memilih transisi antarastartdanenddengan mengklik panah di antara keduanya. - Bagian – Di bawah ringkasan terdapat jendela bagian yang berubah berdasarkan item ringkasan yang saat ini dipilih. Pada gambar ini, informasi
startConstraintSetditampilkan di jendela pilihan. - Atribut – Panel atribut menampilkan dan memungkinkan Anda mengedit atribut item yang saat ini dipilih dari ringkasan atau jendela pilihan. Pada gambar ini, atribut untuk
startConstraintSetditampilkan.
Langkah 3: Tentukan batasan awal dan akhir
Semua animasi dapat ditentukan dalam hal awal dan akhir. Awal menjelaskan tampilan layar sebelum animasi, dan akhir menjelaskan tampilan layar setelah animasi selesai. MotionLayout bertanggung jawab untuk mencari tahu cara menganimasikan antara status awal dan akhir (dari waktu ke waktu).
MotionScene menggunakan tag ConstraintSet untuk menentukan status awal dan akhir. ConstraintSet adalah sekumpulan batasan yang dapat diterapkan pada tampilan. Ini mencakup batasan lebar, tinggi, dan ConstraintLayout. Selain itu, atribut seperti alpha juga disertakan. Tidak berisi tampilan itu sendiri, hanya batasan pada tampilan tersebut.
Batasan apa pun yang ditentukan dalam ConstraintSet akan menggantikan batasan yang ditentukan dalam file tata letak. Jika Anda menentukan batasan di tata letak dan MotionScene, hanya batasan di MotionScene yang diterapkan.
Pada langkah ini, Anda akan membatasi tampilan bintang agar dimulai di bagian atas layar, dan berakhir di bagian bawah layar.
Anda dapat menyelesaikan langkah ini menggunakan Editor Gerakan, atau dengan mengedit teks activity_step1_scene.xml secara langsung.
- Pilih
startConstraintSet di panel ringkasan

- Di panel pilihan, pilih
red_star. Saat ini, Source oflayoutditampilkan – artinya tidak dibatasi dalamConstraintSetini. Gunakan ikon pensil di kanan atas untuk Buat Batasan

- Pastikan
red_starmenampilkan SumberstartsaatstartConstraintSetdipilih di panel ringkasan. - Di panel Attributes, dengan
red_stardipilih distartConstraintSet, tambahkan Batasan di bagian atas dan mulai dengan mengklik tombol + biru.

- Buka
xml/activity_step1_scene.xmluntuk melihat kode yang dihasilkan Motion Editor untuk batasan ini.
activity_step1_scene.xml
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
ConstraintSet memiliki id @id/start, dan menentukan semua batasan yang akan diterapkan ke semua tampilan di MotionLayout. Karena MotionLayout ini hanya memiliki satu tampilan, maka hanya memerlukan satu Constraint.
Constraint di dalam ConstraintSet menentukan ID tampilan yang dibatasinya, @id/red_star yang ditentukan di activity_step1.xml. Penting untuk diperhatikan bahwa tag Constraint hanya menentukan batasan dan informasi tata letak. Tag Constraint tidak mengetahui bahwa tag tersebut diterapkan ke ImageView.
Batasan ini menentukan tinggi, lebar, dan dua batasan lainnya yang diperlukan untuk membatasi tampilan red_star ke awal atas induknya.
- Pilih
endConstraintSet di panel ringkasan.

- Ikuti langkah-langkah yang sama seperti sebelumnya untuk menambahkan
Constraintuntukred_stardiendConstraintSet. - Untuk menggunakan Motion Editor guna menyelesaikan langkah ini, tambahkan batasan ke
bottomdanenddengan mengklik tombol + berwarna biru.

- Kode dalam XML akan terlihat seperti ini:
activitiy_step1_scene.xml
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
Sama seperti @id/start, ConstraintSet ini memiliki satu Constraint di @id/red_star. Kali ini, batasi ke ujung bawah layar.
Anda tidak harus menamainya @id/start dan @id/end, tetapi lebih mudah jika Anda melakukannya.
Langkah 4: Tentukan transisi
Setiap MotionScene juga harus menyertakan setidaknya satu transisi. Transisi menentukan setiap bagian dari satu animasi, dari awal hingga akhir.
Transisi harus menentukan ConstraintSet awal dan akhir untuk transisi. Transisi juga dapat menentukan cara mengubah animasi dengan cara lain, seperti durasi menjalankan animasi atau cara menganimasikan dengan menarik tampilan.
- Motion Editor membuat transisi untuk kita secara default saat membuat file MotionScene. Buka
activity_step1_scene.xmluntuk melihat transisi yang dihasilkan.
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
Inilah semua yang dibutuhkan MotionLayout untuk membuat animasi. Melihat setiap atribut:
constraintSetStartakan diterapkan ke tampilan saat animasi dimulai.constraintSetEndakan diterapkan ke tampilan di akhir animasi.durationmenentukan lamanya waktu animasi yang diperlukan dalam milidetik.
MotionLayout kemudian akan menentukan jalur antara batasan awal dan akhir, lalu menganimasikannya selama durasi yang ditentukan.
Langkah 5: Lihat pratinjau animasi di Editor Gerakan

Animasi: Video tentang cara memutar pratinjau transisi di Editor Gerakan
- Buka Editor Gerakan dan pilih transisi dengan mengklik panah di antara
startdanenddi panel ringkasan.

- Panel pilihan menampilkan kontrol pemutaran dan panel geser saat transisi dipilih. Klik putar atau tarik posisi saat ini untuk melihat pratinjau animasi.

Langkah 6: Tambahkan pengendali saat diklik
Anda memerlukan cara untuk memulai animasi. Salah satu cara untuk melakukannya adalah dengan membuat MotionLayout merespons peristiwa klik pada @id/red_star.
- Buka editor gerakan dan pilih transisi dengan mengklik panah di antara awal dan akhir di panel ringkasan.

- Klik
Create click or swipe handler di toolbar untuk panel ringkasan . Tindakan ini menambahkan pengendali yang akan memulai transisi. - Pilih Click Handler dari pop-up

- Ubah Lihat Untuk Klik menjadi
red_star.

- Klik Tambahkan pengendali klik diwakili oleh titik kecil pada Editor Gerakan Transisi.

- Setelah transisi dipilih di panel ringkasan, tambahkan atribut
clickActiondaritoggleke pengendali OnClick yang baru saja Anda tambahkan di panel atribut.

- Buka
activity_step1_scene.xmluntuk melihat kode yang dihasilkan Motion Editor
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/red_star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
Transition memberi tahu MotionLayout untuk menjalankan animasi sebagai respons terhadap peristiwa klik menggunakan tag <OnClick>. Melihat setiap atribut:
targetIdadalah tampilan yang harus dipantau untuk klik.clickActiondaritoggleakan beralih antara status awal dan akhir saat diklik. Anda dapat melihat opsi lain untukclickActiondi dokumentasi.
- Jalankan kode Anda, klik Langkah 1, lalu klik bintang merah dan lihat animasinya.
Langkah 5: Cara kerja animasi
Jalankan aplikasi. Anda akan melihat animasi berjalan saat mengklik bintang.

File scene gerak yang telah selesai menentukan satu Transition yang mengarah ke ConstraintSet awal dan akhir.
Di awal animasi (@id/start), ikon bintang dibatasi ke bagian atas awal layar. Di akhir animasi (@id/end), ikon bintang dibatasi ke ujung bawah layar.
<?xml version="1.0" encoding="utf-8"?>
<!-- Describe the animation for activity_step1.xml -->
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
</MotionScene>
4. Membuat animasi berdasarkan peristiwa penarikan
Untuk langkah ini, Anda akan membuat animasi yang merespons peristiwa penarikan pengguna (saat pengguna menggeser layar) untuk menjalankan animasi. MotionLayout mendukung pelacakan peristiwa sentuhan untuk memindahkan tampilan, serta gestur melempar berbasis fisika untuk membuat gerakan yang lancar.
Langkah 1: Periksa kode awal
- Untuk memulai, buka file tata letak
activity_step2.xml, yang memilikiMotionLayoutyang ada. Lihat kodenya.
activity_step2.xml
<!-- initial code -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/step2" >
<ImageView
android:id="@+id/left_star"
...
/>
<ImageView
android:id="@+id/right_star"
...
/>
<ImageView
android:id="@+id/red_star"
...
/>
<TextView
android:id="@+id/credits"
...
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Tata letak ini menentukan semua tampilan untuk animasi. Tiga ikon bintang tidak dibatasi dalam tata letak karena akan dianimasikan dalam adegan gerakan.
Kredit TextView memiliki batasan yang diterapkan, karena tetap berada di tempat yang sama selama animasi dan tidak mengubah atribut apa pun.
Langkah 2: Animasi adegan
Sama seperti animasi terakhir, animasi akan ditentukan oleh ConstraintSet, awal dan akhir serta Transition.
Tentukan ConstraintSet awal
- Buka adegan gerak
xml/step2.xmluntuk menentukan animasi. - Tambahkan batasan untuk batasan awal
start. Pada awalnya, ketiga bintang berada di tengah bagian bawah layar. Bintang kanan dan kiri memiliki nilaialpha0.0, yang berarti bintang tersebut sepenuhnya transparan dan tersembunyi.
step2.xml
<!-- TODO apply starting constraints -->
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
Dalam ConstraintSet ini, Anda menentukan satu Constraint untuk setiap bintang. Setiap batasan akan diterapkan oleh MotionLayout di awal animasi.
Setiap tampilan bintang dipusatkan di bagian bawah layar menggunakan batasan awal, akhir, dan bawah. Kedua bintang @id/left_star dan @id/right_star memiliki nilai alfa tambahan yang membuatnya tidak terlihat dan akan diterapkan di awal animasi.
Set batasan start dan end menentukan awal dan akhir animasi. Batasan pada awal, seperti motion:layout_constraintStart_toStartOf akan membatasi awal tampilan ke awal tampilan lain. Hal ini mungkin membingungkan pada awalnya, karena nama start digunakan untuk dan keduanya digunakan dalam konteks batasan. Untuk membantu membedakannya, start dalam layout_constraintStart mengacu pada "awal" tampilan, yaitu kiri dalam bahasa kiri ke kanan dan kanan dalam bahasa kanan ke kiri. Set batasan start mengacu pada awal animasi.
Menentukan ConstraintSet akhir
- Tentukan batasan akhir untuk menggunakan rantai guna memosisikan ketiga bintang bersama-sama di bawah
@id/credits. Selain itu, nilai akhiralphabintang kiri dan kanan akan ditetapkan ke1.0.
step2.xml
<!-- TODO apply ending constraints -->
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintHorizontal_chainStyle="packed"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toStartOf="@id/red_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toEndOf="@id/left_star"
motion:layout_constraintEnd_toStartOf="@id/right_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintStart_toEndOf="@id/red_star"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toBottomOf="@id/credits" />
</ConstraintSet>
Hasil akhirnya adalah tampilan akan menyebar dan naik dari tengah saat dianimasikan.
Selain itu, karena properti alpha ditetapkan pada @id/right_start dan @id/left_star di kedua ConstraintSets, kedua tampilan akan memudar saat animasi berlangsung.
Membuat animasi berdasarkan gesekan pengguna
MotionLayout dapat melacak peristiwa penarikan pengguna, atau gesekan, untuk membuat animasi "lemparan" berbasis fisika. Artinya, tampilan akan terus bergerak jika pengguna melemparnya dan akan melambat seperti objek fisik saat menggelinding di permukaan. Anda dapat menambahkan jenis animasi ini dengan tag OnSwipe di Transition.
- Ganti TODO untuk menambahkan tag
OnSwipedengan<OnSwipe motion:touchAnchorId="@id/red_star" />.
step2.xml
<!-- TODO add OnSwipe tag -->
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end">
<!-- MotionLayout will track swipes relative to this view -->
<OnSwipe motion:touchAnchorId="@id/red_star" />
</Transition>
OnSwipe berisi beberapa atribut, yang paling penting adalah touchAnchorId.
touchAnchorIdadalah tampilan yang dilacak dan bergerak sebagai respons terhadap sentuhan.MotionLayoutakan menjaga tampilan ini pada jarak yang sama dari jari yang menggeser.touchAnchorSidemenentukan sisi tampilan yang harus dilacak. Hal ini penting untuk tampilan yang diubah ukurannya, mengikuti jalur yang rumit, atau memiliki satu sisi yang bergerak lebih cepat daripada sisi lainnya.dragDirectionmenentukan arah mana yang penting untuk animasi ini (atas, bawah, kiri, atau kanan).
Saat MotionLayout memproses peristiwa tarik, pemroses akan didaftarkan di tampilan MotionLayout, bukan tampilan yang ditentukan oleh touchAnchorId. Saat pengguna memulai gestur di mana saja di layar, MotionLayout akan menjaga jarak antara jari pengguna dan touchAnchorSide tampilan touchAnchorId tetap konstan. Jika mereka menyentuh 100 dp dari sisi penahan, misalnya, MotionLayout akan menjaga sisi tersebut 100 dp dari jari mereka selama seluruh animasi.
Cobalah
- Jalankan aplikasi lagi, dan buka layar Langkah 2. Anda akan melihat animasinya.
- Coba "melempar" atau melepaskan jari Anda di tengah animasi untuk mempelajari cara
MotionLayoutmenampilkan animasi berbasis fisika yang lancar.

MotionLayout dapat menganimasikan desain yang sangat berbeda menggunakan fitur dari ConstraintLayout untuk membuat efek yang kaya.
Dalam animasi ini, ketiga tampilan diposisikan relatif terhadap induknya di bagian bawah layar untuk memulai. Pada akhirnya, ketiga tampilan diposisikan relatif terhadap @id/credits dalam rantai.
Meskipun tata letaknya sangat berbeda, MotionLayout akan membuat animasi yang lancar antara awal dan akhir.
5. Mengubah jalur
Pada langkah ini, Anda akan membuat animasi yang mengikuti jalur kompleks selama animasi dan menganimasikan kredit selama gerakan. MotionLayout dapat mengubah jalur yang akan dilalui tampilan antara awal dan akhir menggunakan KeyPosition.
Langkah 1: Pelajari kode yang ada
- Buka
layout/activity_step3.xmldanxml/step3.xmluntuk melihat tata letak dan adegan gerakan yang ada.ImageViewdanTextViewmenampilkan teks bulan dan kredit. - Buka file scene gerak (
xml/step3.xml). Anda akan melihat bahwaTransitiondari@id/starthingga@id/endditentukan. Animasi memindahkan gambar bulan dari kiri bawah layar ke kanan bawah layar menggunakan duaConstraintSets. Teks kredit memudar darialpha="0.0"menjadialpha="1.0"saat bulan bergerak. - Jalankan aplikasi sekarang dan pilih Langkah 3. Anda akan melihat bahwa bulan mengikuti jalur linear (atau garis lurus) dari awal hingga akhir saat Anda mengklik bulan.
Langkah 2: Aktifkan penelusuran bug jalur
Sebelum menambahkan busur ke gerakan bulan, sebaiknya aktifkan proses debug jalur di MotionLayout.
Untuk membantu mengembangkan animasi kompleks dengan MotionLayout, Anda dapat menggambar jalur animasi setiap tampilan. Hal ini berguna saat Anda ingin memvisualisasikan animasi, dan untuk menyempurnakan detail kecil gerakan.
- Untuk mengaktifkan jalur penelusuran bug, buka
layout/activity_step3.xmldan tambahkanmotion:motionDebug="SHOW_PATH"ke tagMotionLayout.
activity_step3.xml
<!-- Add motion:motionDebug="SHOW_PATH" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:motionDebug="SHOW_PATH" >
Setelah mengaktifkan penelusuran bug jalur, saat menjalankan aplikasi lagi, Anda akan melihat jalur semua tampilan yang divisualisasikan dengan garis putus-putus.

- Lingkaran mewakili posisi awal atau akhir satu tampilan.
- Garis mewakili jalur satu tampilan.
- Berlian mewakili
KeyPositionyang mengubah jalur.
Misalnya, dalam animasi ini, lingkaran tengah adalah posisi teks kredit.
Langkah 3: Mengubah jalur
Semua animasi di MotionLayout ditentukan oleh ConstraintSet awal dan akhir yang menentukan tampilan layar sebelum animasi dimulai dan setelah animasi selesai. Secara default, MotionLayout memetakan jalur linear (garis lurus) antara posisi awal dan akhir setiap tampilan yang berubah posisi.
Untuk membuat jalur yang kompleks seperti busur bulan dalam contoh ini, MotionLayout menggunakan KeyPosition untuk mengubah jalur yang diambil tampilan antara awal dan akhir.
- Buka
xml/step3.xmldan tambahkanKeyPositionke adegan. TagKeyPositionditempatkan di dalam tagTransition.

step3.xml
<!-- TODO: Add KeyFrameSet and KeyPosition -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
KeyFrameSet adalah turunan dari Transition, dan merupakan kumpulan semua KeyFrames, seperti KeyPosition, yang harus diterapkan selama transisi.
Saat MotionLayout menghitung jalur untuk bulan antara awal dan akhir, MotionLayout akan mengubah jalur berdasarkan KeyPosition yang ditentukan dalam KeyFrameSet. Anda dapat melihat cara ini mengubah jalur dengan menjalankan aplikasi lagi.
KeyPosition memiliki beberapa atribut yang menjelaskan cara memodifikasi jalur. Yang paling penting adalah:
framePositionadalah angka antara 0 dan 100. Menentukan kapanKeyPositionini harus diterapkan dalam animasi, dengan 1 adalah 1% melalui animasi, dan 99 adalah 99% melalui animasi. Jadi, jika nilainya 50, Anda menerapkannya tepat di tengah.motionTargetadalah tampilan yang jalur pergerakannya diubah olehKeyPositionini.keyPositionTypeadalah caraKeyPositionini mengubah jalur. Nilainya dapat berupaparentRelative,pathRelative, ataudeltaRelative(seperti yang dijelaskan pada langkah berikutnya).percentX | percentYadalah seberapa banyak jalur harus diubah padaframePosition(nilai antara 0,0 dan 1,0, dengan nilai negatif dan nilai >1 diizinkan).
Anda dapat memikirkannya seperti ini: "Pada framePosition ubah jalur motionTarget dengan memindahkannya sebesar percentX atau percentY sesuai dengan koordinat yang ditentukan oleh keyPositionType."
Secara default, MotionLayout akan membulatkan sudut yang muncul akibat modifikasi jalur. Jika melihat animasi yang baru saja Anda buat, Anda dapat melihat bahwa bulan mengikuti jalur melengkung di tikungan. Untuk sebagian besar animasi, inilah yang Anda inginkan, dan jika tidak, Anda dapat menentukan atribut curveFit untuk menyesuaikannya.
Coba
Jika menjalankan aplikasi lagi, Anda akan melihat animasi untuk langkah ini.

Bulan mengikuti busur karena melewati KeyPosition yang ditentukan dalam Transition.
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
Anda dapat membaca KeyPosition ini sebagai: "Pada framePosition 50 (setengah jalan animasi), ubah jalur motionTarget @id/moon dengan memindahkannya sebesar 50% Y (setengah jalan ke bawah layar) sesuai dengan koordinat yang ditentukan oleh parentRelative (seluruh MotionLayout)."
Jadi, di tengah animasi, bulan harus melewati KeyPosition yang 50% ke bawah di layar. KeyPosition ini tidak mengubah gerakan X sama sekali, sehingga bulan akan tetap bergerak dari awal hingga akhir secara horizontal. MotionLayout akan menentukan jalur yang mulus yang melewati KeyPosition ini saat bergerak antara awal dan akhir.
Jika Anda melihat lebih dekat, teks kredit dibatasi oleh posisi bulan. Mengapa tidak bergerak secara vertikal juga?

<Constraint
android:id="@id/credits"
...
motion:layout_constraintBottom_toBottomOf="@id/moon"
motion:layout_constraintTop_toTopOf="@id/moon"
/>
Ternyata, meskipun Anda mengubah jalur yang dilalui bulan, posisi awal dan akhir bulan tidak bergerak secara vertikal sama sekali. KeyPosition tidak mengubah posisi awal atau akhir, sehingga teks kredit dibatasi ke posisi akhir bulan.
Jika ingin kredit bergerak bersama bulan, Anda dapat menambahkan KeyPosition ke kredit, atau mengubah batasan awal pada @id/credits.
Di bagian berikutnya, Anda akan mempelajari berbagai jenis keyPositionType di MotionLayout.
6. Memahami keyPositionType
Di langkah terakhir, Anda menggunakan jenis keyPosition dari parentRelative untuk mengimbangi jalur sebesar 50% dari layar. Atribut keyPositionType menentukan cara MotionLayout akan mengubah jalur sesuai dengan percentX atau percentY.
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
Ada tiga jenis keyPosition yang mungkin: parentRelative, pathRelative, dan deltaRelative. Menentukan jenis akan mengubah sistem koordinat yang digunakan untuk menghitung percentX dan percentY.
Apa itu sistem koordinat?
Sistem koordinat memberikan cara untuk menentukan titik dalam ruang. Batas juga berguna untuk mendeskripsikan posisi di layar.
Sistem koordinat MotionLayout adalah sistem koordinat kartesius. Artinya, mereka memiliki sumbu X dan Y yang ditentukan oleh dua garis tegak lurus. Perbedaan utama di antara keduanya adalah posisi sumbu X pada layar (sumbu Y selalu tegak lurus dengan sumbu X).
Semua sistem koordinat di MotionLayout menggunakan nilai antara 0.0 dan 1.0 pada sumbu X dan Y. Nilai negatif dan nilai yang lebih besar dari 1.0 diizinkan. Jadi, misalnya, nilai percentX sebesar -2.0 berarti bergerak ke arah yang berlawanan dengan sumbu X dua kali.
Jika semua itu terdengar seperti pelajaran Aljabar, lihat gambar di bawah ini.
Koordinat parentRelative

keyPositionType dari parentRelative menggunakan sistem koordinat yang sama dengan layar. Menentukan (0, 0) ke kiri atas seluruh MotionLayout, dan (1, 1) ke kanan bawah.
Anda dapat menggunakan parentRelative kapan pun Anda ingin membuat animasi yang bergerak di seluruh MotionLayout – seperti busur bulan dalam contoh ini.
Namun, jika Anda ingin mengubah jalur relatif terhadap gerakan, misalnya membuatnya sedikit melengkung, dua sistem koordinat lainnya adalah pilihan yang lebih baik.
Koordinat deltaRelatif

Delta adalah istilah matematika untuk perubahan, jadi deltaRelative adalah cara untuk mengatakan "perubahan relatif". Dalam deltaRelative koordinat(0,0) adalah posisi awal tampilan, dan (1,1) adalah posisi akhir. Sumbu X dan Y sejajar dengan layar.
Sumbu X selalu horizontal di layar, dan sumbu Y selalu vertikal di layar. Dibandingkan dengan parentRelative, perbedaan utamanya adalah koordinat hanya menjelaskan bagian layar tempat tampilan akan bergerak.
deltaRelative adalah sistem koordinat yang bagus untuk mengontrol gerakan horizontal atau vertikal secara terpisah. Misalnya, Anda dapat membuat animasi yang menyelesaikan gerakan vertikal (Y) pada 50%, dan terus menganimasikan secara horizontal (X).
pathRelative koordinat

Sistem koordinat terakhir di MotionLayout adalah pathRelative. Animasi ini cukup berbeda dari dua lainnya karena sumbu X mengikuti jalur gerakan dari awal hingga akhir. Jadi, (0,0) adalah posisi awal, dan (1,0) adalah posisi akhir.
Mengapa Anda menginginkan hal ini? Pada pandangan pertama, hal ini cukup mengejutkan, terutama karena sistem koordinat ini bahkan tidak selaras dengan sistem koordinat layar.
Ternyata pathRelative sangat berguna untuk beberapa hal.
- Mempercepat, memperlambat, atau menghentikan tampilan selama sebagian animasi. Karena dimensi X akan selalu cocok dengan jalur yang diambil tampilan secara persis, Anda dapat menggunakan
pathRelativeKeyPositionuntuk mengubahframePositionmana yang dicapai pada titik tertentu dalam jalur tersebut. Jadi,KeyPositionpadaframePosition="50"denganpercentX="0.1"akan menyebabkan animasi memerlukan waktu 50% untuk menempuh 10% pertama gerakan. - Menambahkan busur halus ke jalur. Karena dimensi Y selalu tegak lurus terhadap gerakan, mengubah Y akan mengubah jalur ke kurva relatif terhadap gerakan keseluruhan.
- Menambahkan dimensi kedua saat
deltaRelativetidak akan berfungsi. Untuk gerakan horizontal dan vertikal sepenuhnya,deltaRelativehanya akan membuat satu dimensi yang berguna. Namun,pathRelativeakan selalu membuat koordinat X dan Y yang dapat digunakan.
Di langkah berikutnya, Anda akan mempelajari cara membuat jalur yang lebih kompleks menggunakan lebih dari satu KeyPosition.
7. Membangun jalur yang kompleks
Melihat animasi yang Anda buat di langkah terakhir, animasi tersebut memang menciptakan kurva yang mulus, tetapi bentuknya bisa lebih menyerupai "bulan".
Mengubah jalur dengan beberapa elemen KeyPosition
MotionLayout dapat mengubah jalur lebih lanjut dengan menentukan KeyPosition sebanyak yang diperlukan untuk mendapatkan gerakan apa pun. Untuk animasi ini, Anda akan membuat busur, tetapi Anda dapat membuat bulan melompat naik dan turun di tengah layar, jika Anda mau.
- Buka
xml/step4.xml. Anda akan melihat bahwa video tersebut memiliki jumlah penayangan yang sama danKeyFrameyang Anda tambahkan pada langkah terakhir. - Untuk melengkapi bagian atas kurva, tambahkan dua
KeyPositionslagi ke jalur@id/moon, satu tepat sebelum mencapai bagian atas, dan satu lagi setelahnya.

step4.xml
<!-- TODO: Add two more KeyPositions to the KeyFrameSet here -->
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
KeyPositions ini akan diterapkan 25% dan 75% selama animasi, dan menyebabkan @id/moon bergerak melalui jalur yang berjarak 60% dari bagian atas layar. Jika digabungkan dengan KeyPosition yang sudah ada sebesar 50%, hal ini akan menciptakan busur yang mulus untuk diikuti bulan.
Di MotionLayout, Anda dapat menambahkan KeyPositions sebanyak yang diperlukan untuk mendapatkan jalur gerakan yang diinginkan. MotionLayout akan menerapkan setiap KeyPosition pada framePosition yang ditentukan, dan mencari tahu cara membuat gerakan halus yang melewati semua KeyPositions.
Coba
- Jalankan kembali aplikasi. Buka Langkah 4 untuk melihat cara kerja animasi. Saat Anda mengklik bulan, bulan akan mengikuti jalur dari awal hingga akhir, melewati setiap
KeyPositionyang ditentukan dalamKeyFrameSet.
Menjelajahi sendiri
Sebelum melanjutkan ke jenis KeyFrame lainnya, coba tambahkan beberapa KeyPositions lagi ke KeyFrameSet untuk melihat jenis efek yang dapat Anda buat hanya dengan menggunakan KeyPosition.
Berikut adalah salah satu contoh yang menunjukkan cara membuat jalur kompleks yang bergerak maju mundur selama animasi.

step4.xml
<!-- Complex paths example: Dancing moon -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
motion:percentX="0.3"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
</KeyFrameSet>
Setelah selesai menjelajahi KeyPosition, di langkah berikutnya Anda akan mempelajari jenis KeyFrames lainnya.
8. Mengubah atribut selama gerakan
Membangun animasi dinamis sering kali berarti mengubah size, rotation, atau alpha tampilan saat animasi berlangsung. MotionLayout mendukung animasi banyak atribut pada tampilan apa pun menggunakan KeyAttribute.
Pada langkah ini, Anda akan menggunakan KeyAttribute untuk membuat skala dan rotasi bulan. Anda juga akan menggunakan KeyAttribute untuk menunda kemunculan teks hingga bulan hampir menyelesaikan perjalanannya.
Langkah 1: Mengubah ukuran dan memutar dengan KeyAttribute
- Buka
xml/step5.xmlyang berisi animasi yang sama dengan yang Anda buat pada langkah terakhir. Untuk variasi, layar ini menggunakan gambar luar angkasa yang berbeda sebagai latar belakang. - Untuk membuat ukuran bulan bertambah besar dan berputar, tambahkan dua tag
KeyAttributediKeyFrameSetpadakeyFrame="50"dankeyFrame="100"

step5.xml
<!-- TODO: Add KeyAttributes to rotate and resize @id/moon -->
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon"
android:scaleY="2.0"
android:scaleX="2.0"
android:rotation="-360"
/>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon"
android:rotation="-720"
/>
KeyAttributes ini diterapkan pada 50% dan 100% animasi. KeyAttribute pertama pada 50% akan terjadi di bagian atas busur, dan menyebabkan tampilan berukuran dua kali lipat serta berputar -360 derajat (atau satu lingkaran penuh). KeyAttribute kedua akan menyelesaikan rotasi kedua ke -720 derajat (dua lingkaran penuh) dan mengecilkan ukuran kembali ke ukuran reguler karena nilai scaleX dan scaleY secara default adalah 1,0.
Sama seperti KeyPosition, KeyAttribute menggunakan framePosition dan motionTarget untuk menentukan kapan KeyFrame diterapkan, dan tampilan mana yang akan diubah. MotionLayout akan melakukan interpolasi antara KeyPositions untuk membuat animasi yang lancar.
Dukungan KeyAttributes atribut yang dapat diterapkan ke semua tampilan. Atribut ini mendukung perubahan atribut dasar seperti visibility, alpha, atau elevation. Anda juga dapat mengubah rotasi seperti yang Anda lakukan di sini, memutar dalam tiga dimensi dengan rotateX dan rotateY, menskalakan ukuran dengan scaleX dan scaleY, atau menerjemahkan posisi tampilan dalam X, Y, atau Z.
Langkah 2: Menunda kemunculan kredit
Salah satu tujuan langkah ini adalah memperbarui animasi sehingga teks kredit tidak muncul hingga animasi hampir selesai.
- Untuk menunda kemunculan kredit, tentukan
KeyAttributelain yang memastikan bahwaalphaakan tetap 0 hinggakeyPosition="85".MotionLayoutakan tetap bertransisi dengan lancar dari alfa 0 hingga 100, tetapi akan melakukannya selama 15% terakhir animasi.
step5.xml
<!-- TODO: Add KeyAttribute to delay the appearance of @id/credits -->
<KeyAttribute
motion:framePosition="85"
motion:motionTarget="@id/credits"
android:alpha="0.0"
/>
KeyAttribute ini mempertahankan alpha @id/credits pada 0,0 untuk 85% pertama animasi. Karena dimulai dengan nilai alfa 0, artinya animasi ini tidak akan terlihat selama 85% pertama durasi animasi.
Efek akhir dari KeyAttribute ini adalah kredit muncul di akhir animasi. Hal ini memberikan kesan bahwa mereka berkoordinasi dengan bulan yang turun di sudut kanan layar.
Dengan menunda animasi pada satu tampilan saat tampilan lain bergerak seperti ini, Anda dapat membuat animasi mengesankan yang terasa dinamis bagi pengguna.
Coba
- Jalankan aplikasi lagi dan buka Langkah 5 untuk melihat cara kerja animasi. Saat Anda mengklik bulan, bulan akan mengikuti jalur dari awal hingga akhir, melewati setiap
KeyAttributeyang ditentukan dalamKeyFrameSet.

Karena Anda memutar bulan dua lingkaran penuh, bulan akan melakukan putaran ganda ke belakang, dan kredit akan ditunda kemunculannya hingga animasi hampir selesai.
Jelajahi sendiri
Sebelum Anda beralih ke jenis KeyFrame terakhir, coba ubah atribut standar lainnya di KeyAttributes. Misalnya, coba ubah rotation menjadi rotationX untuk melihat animasi yang dihasilkan.
Berikut adalah daftar atribut standar yang dapat Anda coba:
android:visibilityandroid:alphaandroid:elevationandroid:rotationandroid:rotationXandroid:rotationYandroid:scaleXandroid:scaleYandroid:translationXandroid:translationYandroid:translationZ
9. Mengubah atribut khusus
Animasi kaya melibatkan perubahan warna atau atribut tampilan lainnya. Meskipun MotionLayout dapat menggunakan KeyAttribute untuk mengubah atribut standar yang tercantum dalam tugas sebelumnya, Anda menggunakan CustomAttribute untuk menentukan atribut lainnya.
CustomAttribute dapat digunakan untuk menetapkan nilai apa pun yang memiliki setter. Misalnya, Anda dapat menetapkan backgroundColor pada View menggunakan CustomAttribute. MotionLayout akan menggunakan refleksi untuk menemukan setter, lalu memanggilnya berulang kali untuk menganimasikan tampilan.
Pada langkah ini, Anda akan menggunakan CustomAttribute untuk menetapkan atribut colorFilter pada bulan untuk membuat animasi yang ditunjukkan di bawah.

Menentukan atribut kustom
- Untuk memulai, buka
xml/step6.xmlyang berisi animasi yang sama dengan yang Anda buat pada langkah terakhir. - Untuk membuat bulan berubah warna, tambahkan dua
KeyAttributedenganCustomAttributediKeyFrameSetpadakeyFrame="0",keyFrame="50", dankeyFrame="100".

step6.xml
<!-- TODO: Add Custom attributes here -->
<KeyAttribute
motion:framePosition="0"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFB612"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
Anda menambahkan CustomAttribute di dalam KeyAttribute. CustomAttribute akan diterapkan pada framePosition yang ditentukan oleh KeyAttribute.
Di dalam CustomAttribute, Anda harus menentukan attributeName dan satu nilai yang akan ditetapkan.
motion:attributeNameadalah nama setter yang akan dipanggil oleh atribut kustom ini. Dalam contoh ini,setColorFilterdiDrawableakan dipanggil.motion:custom*Valueadalah nilai kustom dari jenis yang tercantum dalam nama, dalam contoh ini nilai kustom adalah warna yang ditentukan.
Nilai kustom dapat memiliki salah satu jenis berikut:
- Warna
- Bilangan bulat
- Float
- String
- Dimensi
- Boolean
Dengan menggunakan API ini, MotionLayout dapat menganimasikan apa pun yang menyediakan setter pada tampilan apa pun.
Coba
- Jalankan aplikasi lagi dan buka Langkah 6 untuk melihat cara kerja animasi. Saat Anda mengklik bulan, bulan akan mengikuti jalur dari awal hingga akhir, melewati setiap
KeyAttributeyang ditentukan dalamKeyFrameSet.

Saat Anda menambahkan lebih banyak KeyFrames, MotionLayout mengubah jalur bulan dari garis lurus menjadi kurva kompleks, menambahkan salto ganda, pengubahan ukuran, dan perubahan warna di tengah animasi.
Dalam animasi nyata, Anda sering kali menganimasikan beberapa tampilan secara bersamaan, mengontrol gerakannya di sepanjang jalur dan kecepatan yang berbeda. Dengan menentukan KeyFrame yang berbeda untuk setiap tampilan, Anda dapat mengatur koreografi animasi kompleks yang menganimasikan beberapa tampilan dengan MotionLayout.
10. Peristiwa tarik dan jalur kompleks
Pada langkah ini, Anda akan mempelajari cara menggunakan OnSwipe dengan jalur yang kompleks. Sejauh ini, animasi bulan telah dipicu oleh pemroses OnClick dan berjalan selama durasi tetap.
Mengontrol animasi yang memiliki jalur kompleks menggunakan OnSwipe, seperti animasi bulan yang telah Anda buat dalam beberapa langkah terakhir, memerlukan pemahaman tentang cara kerja OnSwipe.
Langkah 1: Jelajahi perilaku OnSwipe
- Buka
xml/step7.xmldan temukan deklarasiOnSwipeyang ada.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
/>
- Jalankan aplikasi di perangkat Anda dan buka Langkah 7. Lihat apakah Anda dapat menghasilkan animasi yang lancar dengan menarik bulan di sepanjang jalur busur.
Saat Anda menjalankan animasi ini, hasilnya tidak terlalu bagus. Setelah bulan mencapai puncak busur, bulan akan mulai melompat-lompat.

Untuk memahami bug, pertimbangkan apa yang terjadi saat pengguna menyentuh tepat di bawah bagian atas busur. Karena tag OnSwipe memiliki motion:touchAnchorSide="bottom" MotionLayout akan mencoba membuat jarak antara jari dan bagian bawah tampilan tetap konstan selama animasi.
Namun, karena bagian bawah bulan tidak selalu bergerak ke arah yang sama, ia akan naik lalu turun kembali, MotionLayout tidak tahu apa yang harus dilakukan saat pengguna baru saja melewati bagian atas busur. Untuk mempertimbangkan hal ini, karena Anda melacak bagian bawah bulan, di mana seharusnya bulan ditempatkan saat pengguna menyentuh di sini?

Langkah 2: Gunakan sisi kanan
Untuk menghindari bug seperti ini, penting untuk selalu memilih touchAnchorId dan touchAnchorSide yang selalu bergerak ke satu arah selama durasi seluruh animasi.
Dalam animasi ini, sisi right dan sisi left bulan akan bergerak melintasi layar dalam satu arah.
Namun, bottom dan top akan berbalik arah. Saat OnSwipe mencoba melacaknya, OnSwipe akan bingung saat arahnya berubah.
- Agar animasi ini mengikuti peristiwa sentuh, ubah
touchAnchorSidemenjadiright.
step7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="right"
/>
Langkah 3: Gunakan dragDirection
Anda juga dapat menggabungkan dragDirection dengan touchAnchorSide untuk membuat jalur samping bergerak ke arah yang berbeda dari biasanya. touchAnchorSide masih penting untuk hanya berjalan dalam satu arah, tetapi Anda dapat memberi tahu MotionLayout arah yang harus dilacak. Misalnya, Anda dapat mempertahankan touchAnchorSide="bottom", tetapi menambahkan dragDirection="dragRight". Tindakan ini akan menyebabkan MotionLayout melacak posisi bagian bawah tampilan, tetapi hanya mempertimbangkan lokasinya saat bergerak ke kanan (mengabaikan gerakan vertikal). Jadi, meskipun bagian bawah naik dan turun, bagian tersebut akan tetap dianimasikan dengan benar menggunakan OnSwipe.
- Perbarui
OnSwipeuntuk melacak pergerakan bulan dengan benar.
step7.xml
<!-- Using dragDirection to control the direction of drag tracking →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragRight"
/>
Coba
- Jalankan aplikasi lagi dan coba tarik bulan di sepanjang jalur. Meskipun mengikuti alur yang kompleks,
MotionLayoutakan dapat memproses animasi sebagai respons terhadap peristiwa geser.

11. Menjalankan gerakan dengan kode
MotionLayout dapat digunakan untuk membuat animasi yang kaya saat digunakan dengan CoordinatorLayout. Pada langkah ini, Anda akan membuat header yang dapat diciutkan menggunakan MotionLayout.
Langkah 1: Pelajari kode yang ada
- Untuk memulai, buka
layout/activity_step8.xml. - Di
layout/activity_step8.xml, Anda melihat bahwaCoordinatorLayoutdanAppBarLayoutyang berfungsi sudah dibuat.
activity_step8.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="180dp">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
... >
...
</androidx.constraintlayout.motion.widget.MotionLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
...
motion:layout_behavior="@string/appbar_scrolling_view_behavior" >
...
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Tata letak ini menggunakan CoordinatorLayout untuk membagikan informasi scrolling antara NestedScrollView dan AppBarLayout. Jadi, saat NestedScrollView di-scroll ke atas, NestedScrollView akan memberi tahu AppBarLayout tentang perubahan tersebut. Begitulah cara Anda menerapkan toolbar yang menyusut seperti ini di Android—scroll teks akan "dikoordinasikan" dengan header yang menyusut.
Scene gerakan yang dituju @id/motion_layout mirip dengan scene gerakan di langkah terakhir. Namun, deklarasi OnSwipe dihapus agar dapat berfungsi dengan CoordinatorLayout.
- Jalankan aplikasi, lalu buka Langkah 8. Anda akan melihat bahwa saat Anda men-scroll teks, bulan tidak bergerak.
Langkah 2: Membuat MotionLayout dapat di-scroll
- Untuk membuat tampilan
MotionLayoutmen-scroll segera setelahNestedScrollViewmen-scroll, tambahkanmotion:minHeightdanmotion:layout_scrollFlagskeMotionLayout.
activity_step8.xml
<!-- Add minHeight and layout_scrollFlags to the MotionLayout -->
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layoutDescription="@xml/step8"
motion:motionDebug="SHOW_PATH"
android:minHeight="80dp"
motion:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed" >
- Jalankan kembali aplikasi dan buka Langkah 8. Anda akan melihat bahwa
MotionLayoutmenciut saat Anda men-scroll ke atas. Namun, animasi belum berjalan berdasarkan perilaku scroll.
Langkah 3: Menggerakkan gerakan dengan kode
- Buka
Step8Activity.kt. Edit fungsicoordinateMotion()untuk memberi tahuMotionLayouttentang perubahan posisi scroll.
Step8Activity.kt
// TODO: set progress of MotionLayout based on an AppBarLayout.OnOffsetChangedListener
private fun coordinateMotion() {
val appBarLayout: AppBarLayout = findViewById(R.id.appbar_layout)
val motionLayout: MotionLayout = findViewById(R.id.motion_layout)
val listener = AppBarLayout.OnOffsetChangedListener { unused, verticalOffset ->
val seekPosition = -verticalOffset / appBarLayout.totalScrollRange.toFloat()
motionLayout.progress = seekPosition
}
appBarLayout.addOnOffsetChangedListener(listener)
}
Kode ini akan mendaftarkan OnOffsetChangedListener yang akan dipanggil setiap kali pengguna men-scroll dengan offset scroll saat ini.
MotionLayout mendukung pencarian transisinya dengan menyetel properti progres. Untuk mengonversi antara verticalOffset dan progres persentase, bagi dengan total rentang scroll.
Coba
- Deploy aplikasi lagi dan jalankan animasi Langkah 8. Anda akan melihat bahwa
MotionLayoutakan memajukan animasi berdasarkan posisi scroll.

Anda dapat membuat animasi toolbar yang menyusut dinamis kustom menggunakan MotionLayout. Dengan menggunakan urutan KeyFrames, Anda dapat mencapai efek yang sangat berani.
12. Selamat
Codelab ini membahas API dasar MotionLayout.
Untuk melihat contoh penerapan MotionLayout lainnya, lihat contoh resmi. Pastikan juga untuk melihat dokumentasi.
Pelajari Lebih Lanjut
MotionLayout mendukung lebih banyak fitur yang tidak dibahas dalam codelab ini, seperti KeyCycle, yang memungkinkan Anda mengontrol jalur atau atribut dengan siklus berulang, dan KeyTimeCycle, yang memungkinkan Anda membuat animasi berdasarkan waktu jam. Lihat contoh untuk melihat contoh masing-masing.
Untuk link ke codelab lain dalam kursus ini, lihat halaman landing codelab Android Lanjutan di Kotlin.