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 pergerakan ukuran dan posisi, Anda dapat menentukan parameter boundsTransform yang berbeda pada Modifier.sharedElement().
Hal ini memberikan posisi Rect awal dan posisi Rect target.
Misalnya, untuk membuat teks dalam contoh sebelumnya bergerak dengan gerakan busur
motion, 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.
boundsTransform yang berbedaMode ubah ukuran
Saat menganimasikan antara dua batas bersama, Anda dapat menetapkan parameter resizeMode ke RemeasureToBounds atau ScaleToBounds. Parameter ini menentukan cara elemen bersama bertransisi antara dua status. ScaleToBounds pertama-tama 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" antara status.
Sebaliknya, RemeasureToBounds mengukur ulang dan menata ulang tata letak turunan sharedBounds dengan batasan tetap animasi berdasarkan ukuran target. Pengukuran ulang dipicu oleh perubahan ukuran batas, yang berpotensi menjadi setiap frame.
Untuk composable Text, ScaleToBounds direkomendasikan, karena menghindari tata letak ulang dan pengaliran 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 dua mode ubah 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 melakukan navigasi antara layar tertentu (misalnya, hanya dari A ke B), sekaligus menonaktifkannya untuk layar lainnya.
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 yang sedang berlangsung, elemen tersebut akan tetap menyelesaikan animasi yang sedang berlangsung saat ini untuk mencegah penghapusan animasi yang sedang berlangsung secara tidak sengaja. Jika Anda perlu menghapus elemen saat animasi sedang berlangsung, Anda dapat mengganti shouldKeepEnabledForOngoingAnimation di antarmuka SharedContentConfig untuk menampilkan nilai salah (false).
Melewati ke tata letak akhir
Secara default, saat bertransisi antara dua tata letak, ukuran tata letak akan dianimasikan antara status awal dan akhir. 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. Dalam contoh pertama, teks akan mengalir ulang saat dimasukkan karena penampung bertambah ukurannya. Dalam contoh kedua, teks tidak mengalir ulang saat bertambah. Menambahkan Modifier.skipToLookaheadSize() akan mencegah pengaliran ulang saat bertambah.
Tidak ada |
|
|---|---|
Klip dan overlay
Agar elemen bersama dapat berbagi antara composable yang berbeda, rendering composable ditingkatkan ke 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 non-bersama lainnya. Setelah transisi selesai, elemen akan dihilangkan dari overlay ke DrawScope miliknya sendiri.
Untuk mengklip elemen bersama ke 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 Anda perlu memastikan bahwa elemen bersama tidak pernah dirender di luar penampung induk, Anda dapat menetapkan clipInOverlayDuringTransition pada sharedElement(). Secara default, untuk batas bersama bertingkat, clipInOverlayDuringTransition menggunakan jalur klip dari sharedBounds() induk.
Untuk mendukung elemen UI tertentu, seperti panel bawah atau tombol tindakan mengambang, agar selalu berada di atas selama transisi elemen bersama, gunakan
Modifier.renderInSharedTransitionScopeOverlay(). Secara default, pengubah ini menyimpan 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 non-bersama dianimasikan serta tetap berada di atas composable lainnya sebelum transisi. Dalam kasus seperti itu, 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 pada sharedElement() ke salah (false).
Memberi tahu tata letak saudara tentang perubahan pada ukuran elemen bersama
Secara default, sharedBounds() dan sharedElement() tidak memberi tahu penampung induk tentang perubahan ukuran apa pun saat tata letak bertransisi.
Untuk menyebarkan perubahan ukuran ke penampung induk saat bertransisi, ubah parameter placeholderSize ke PlaceholderSize.AnimatedSize. Tindakan ini akan menyebabkan item bertambah besar atau mengecil. 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) |
|---|---|