Untuk menyesuaikan cara animasi transisi elemen bersama berjalan, ada beberapa parameter yang dapat digunakan untuk mengubah cara transisi elemen bersama.
Spesifikasi animasi
Untuk mengubah spesifikasi animasi yang digunakan untuk gerakan ukuran dan posisi, Anda dapat
menentukan parameter boundsTransform yang berbeda di Modifier.sharedElement().
Hal ini memberikan posisi Rect awal dan posisi Rect target.
Misalnya, untuk membuat teks dalam contoh sebelumnya bergerak dengan gerakan
lengkung, tentukan parameter boundsTransform untuk menggunakan spesifikasi keyframes:
val textBoundsTransform = BoundsTransform { initialBounds, targetBounds -> keyframes { durationMillis = boundsAnimationDurationMillis initialBounds at 0 using ArcMode.ArcBelow using FastOutSlowInEasing targetBounds at boundsAnimationDurationMillis } } Text( "Cupcake", fontSize = 28.sp, modifier = Modifier.sharedBounds( rememberSharedContentState(key = "title"), animatedVisibilityScope = animatedVisibilityScope, boundsTransform = textBoundsTransform ) )
Anda dapat menggunakan AnimationSpec apa pun. Contoh ini menggunakan spesifikasi keyframes.
boundsTransformMode ubah ukuran
Saat menganimasikan antara dua batas bersama, Anda dapat menetapkan parameter resizeMode
ke RemeasureToBounds atau ScaleToBounds. Parameter ini menentukan cara
elemen bersama bertransisi di antara dua status. ScaleToBounds terlebih dahulu
mengukur tata letak turunan dengan batasan lookahead (atau target). Kemudian, tata letak stabil turunan diskalakan agar sesuai dengan batas bersama.
ScaleToBounds dapat dianggap sebagai "skala grafis" di antara status.
Sebaliknya, RemeasureToBounds mengukur ulang dan mengatur ulang tata letak turunan
sharedBounds dengan batasan tetap animasi berdasarkan ukuran target. Pengukuran ulang dipicu oleh perubahan ukuran batas, yang berpotensi terjadi di setiap frame.
Untuk composable Text, sebaiknya gunakan ScaleToBounds karena dapat menghindari tata letak ulang
dan penataan ulang teks ke baris yang berbeda. RemeasureToBounds direkomendasikan
untuk batas yang memiliki rasio aspek berbeda, dan jika Anda menginginkan kontinuitas yang lancar
antara dua elemen bersama.
Perbedaan antara kedua mode pengubahan ukuran dapat dilihat dalam contoh berikut:
|
|
|---|---|
Mengaktifkan dan menonaktifkan elemen bersama secara dinamis
Secara default, sharedElement() dan sharedBounds() dikonfigurasi untuk menganimasikan
perubahan tata letak setiap kali kunci yang cocok ditemukan dalam status target. Namun,
Anda mungkin ingin menonaktifkan animasi ini secara dinamis berdasarkan kondisi tertentu,
seperti arah navigasi atau status UI saat ini.
Untuk mengontrol apakah transisi elemen bersama terjadi, Anda dapat menyesuaikan
SharedContentConfig yang diteruskan ke rememberSharedContentState(). Properti isEnabled
menentukan apakah elemen bersama aktif.
Contoh berikut menunjukkan cara menentukan konfigurasi yang hanya mengaktifkan transisi bersama saat berpindah di antara layar tertentu (misalnya, hanya dari A ke B), sekaligus menonaktifkannya untuk layar lain.
SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean // For this example, we only enable the transition in one direction // from A -> B and not the other way around. get() = transition.currentState == "A" && transition.targetState == "B" } } when (targetState) { "A" -> Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } "B" -> { Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } } } } }
Secara default, jika elemen bersama dinonaktifkan selama animasi berlangsung, elemen tersebut
tetap menyelesaikan animasi yang sedang berlangsung untuk mencegah penghapusan
animasi yang sedang berjalan secara tidak sengaja. Jika perlu menghapus elemen saat
animasi sedang berlangsung, Anda dapat mengganti
shouldKeepEnabledForOngoingAnimation di antarmuka SharedContentConfig untuk
menampilkan nilai salah.
Lewati ke tata letak akhir
Secara default, saat bertransisi di antara dua tata letak, ukuran tata letak akan dianimasikan antara status awal dan akhirnya. Hal ini mungkin merupakan perilaku yang tidak diinginkan saat menganimasikan konten seperti teks.
Contoh berikut mengilustrasikan teks deskripsi "Lorem Ipsum" yang masuk ke
layar dengan dua cara berbeda. Pada contoh pertama, teks mengalir ulang saat
dimasukkan seiring bertambahnya ukuran penampung. Dalam contoh kedua, teks tidak
mengalir ulang saat bertambah. Menambahkan Modifier.skipToLookaheadSize() akan mencegah penataan ulang
saat bertambah.
Tidak ada |
|
|---|---|
Klip dan overlay
Agar elemen bersama dapat dibagikan di antara composable yang berbeda, rendering composable ditingkatkan menjadi overlay lapisan saat transisi dimulai ke kecocokannya di tujuan. Efeknya adalah elemen tersebut akan keluar dari batas induk dan transformasi lapisannya (misalnya, alfa dan skala).
Elemen ini akan dirender di atas elemen UI lain yang tidak dibagikan. Setelah transisi
selesai, elemen akan dihapus dari overlay ke DrawScope-nya sendiri.
Untuk memotong elemen bersama menjadi bentuk, gunakan fungsi Modifier.clip()
standar. Tempatkan setelah sharedElement():
Image( painter = painterResource(id = R.drawable.cupcake), contentDescription = "Cupcake", modifier = Modifier .size(100.dp) .sharedElement( rememberSharedContentState(key = "image"), animatedVisibilityScope = this@AnimatedContent ) .clip(RoundedCornerShape(16.dp)), contentScale = ContentScale.Crop )
Jika perlu memastikan bahwa elemen bersama tidak pernah dirender di luar penampung
induk, Anda dapat menetapkan clipInOverlayDuringTransition di sharedElement(). Secara
default, untuk batas bersama bertingkat, clipInOverlayDuringTransition menggunakan jalur
klip dari sharedBounds() induk.
Untuk mendukung mempertahankan elemen UI tertentu, seperti panel bawah atau tombol tindakan mengambang (FAB), selalu di atas selama transisi elemen bersama, gunakan Modifier.renderInSharedTransitionScopeOverlay(). Secara default, pengubah
ini mempertahankan konten dalam overlay selama transisi bersama
aktif.
Misalnya, di Jetsnack, BottomAppBar harus ditempatkan di atas
elemen bersama hingga layar tidak terlihat. Menambahkan pengubah
ke composable akan membuatnya tetap ditinggikan.
Tanpa |
Dengan |
|---|---|
Anda mungkin ingin composable yang tidak dibagikan dianimasikan serta
tetap berada di atas composable lain sebelum transisi. Dalam kasus tersebut, gunakan
renderInSharedTransitionScopeOverlay().animateEnterExit() untuk menganimasikan
composable saat transisi elemen bersama berjalan:
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
Dalam kasus yang jarang terjadi, jika Anda tidak ingin elemen bersama dirender dalam
overlay, Anda dapat menetapkan renderInOverlayDuringTransition di sharedElement()
ke false.
Memberi tahu tata letak yang setara tentang perubahan ukuran elemen bersama
Secara default, sharedBounds() dan sharedElement() tidak memberi tahu penampung
induk tentang perubahan ukuran apa pun saat transisi tata letak.
Untuk menerapkan perubahan ukuran ke penampung induk saat bertransisi,
ubah parameter placeholderSize menjadi PlaceholderSize.AnimatedSize. Tindakan ini
akan menyebabkan item bertambah atau berkurang. Semua item lain dalam tata letak merespons
perubahan tersebut.
|
(Perhatikan bagaimana item lain dalam daftar bergerak ke bawah sebagai respons terhadap satu item yang bertambah besar) |
|---|---|