Compose dilengkapi dengan composable dan pengubah bawaan untuk menangani kasus penggunaan animasi umum.
Composable animasi bawaan
Animasikan kemunculan dan penghilangan dengan AnimatedVisibility
![Composable hijau menampilkan dan menyembunyikan dirinya sendiri](https://developer.android.com/static/develop/ui/compose/images/animations/animated_visibility_column.gif?authuser=19&hl=id)
Composable
AnimatedVisibility
menganimasikan muncul dan hilangnya kontennya.
var visible by remember { mutableStateOf(true) } // Animated visibility will eventually remove the item from the composition once the animation has finished. AnimatedVisibility(visible) { // your composable here // ... }
Secara default, konten muncul dengan menjadi jelas dan meluas, serta menghilang dengan memudar dan menyusut. Transisi dapat disesuaikan dengan menentukan EnterTransition
dan ExitTransition
.
var visible by remember { mutableStateOf(true) } val density = LocalDensity.current AnimatedVisibility( visible = visible, enter = slideInVertically { // Slide in from 40 dp from the top. with(density) { -40.dp.roundToPx() } } + expandVertically( // Expand from the top. expandFrom = Alignment.Top ) + fadeIn( // Fade in with the initial alpha of 0.3f. initialAlpha = 0.3f ), exit = slideOutVertically() + shrinkVertically() + fadeOut() ) { Text("Hello", Modifier.fillMaxWidth().height(200.dp)) }
Seperti yang Anda lihat pada contoh di atas, Anda dapat menggabungkan beberapa objek EnterTransition
atau ExitTransition
dengan operator +
, dan masing-masing menerima parameter opsional untuk menyesuaikan perilakunya. Lihat referensi untuk informasi selengkapnya.
Contoh EnterTransition
dan ExitTransition
AnimatedVisibility
juga menawarkan varian yang memerlukan
MutableTransitionState
. Hal ini memungkinkan Anda untuk memicu animasi segera setelah
AnimatedVisibility
ditambahkan ke hierarki komposisi. Hal ini juga berguna untuk
mengamati status animasi.
// Create a MutableTransitionState<Boolean> for the AnimatedVisibility. val state = remember { MutableTransitionState(false).apply { // Start the animation immediately. targetState = true } } Column { AnimatedVisibility(visibleState = state) { Text(text = "Hello, world!") } // Use the MutableTransitionState to know the current animation state // of the AnimatedVisibility. Text( text = when { state.isIdle && state.currentState -> "Visible" !state.isIdle && state.currentState -> "Disappearing" state.isIdle && !state.currentState -> "Invisible" else -> "Appearing" } ) }
Menganimasikan masuk dan keluar untuk turunan
Konten dalam AnimatedVisibility
(turunan langsung atau tidak langsung) dapat menggunakan pengubah
animateEnterExit
untuk menentukan perilaku animasi yang berbeda bagi setiap turunan. Efek visual
untuk setiap turunan ini adalah kombinasi animasi yang ditetapkan
pada composable AnimatedVisibility
serta animasi masuk dan
keluar turunan itu sendiri.
var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn(), exit = fadeOut() ) { // Fade in/out the background and the foreground. Box(Modifier.fillMaxSize().background(Color.DarkGray)) { Box( Modifier .align(Alignment.Center) .animateEnterExit( // Slide in/out the inner box. enter = slideInVertically(), exit = slideOutVertically() ) .sizeIn(minWidth = 256.dp, minHeight = 64.dp) .background(Color.Red) ) { // Content of the notification… } } }
Dalam beberapa kasus, Anda mungkin ingin AnimatedVisibility
tidak menerapkan animasi sama sekali
sehingga turunan dapat memiliki animasinya sendiri dengan menggunakan
animateEnterExit
. Untuk mencapai hal ini, tentukan EnterTransition.None
dan
ExitTransition.None
pada composable AnimatedVisibility
.
Menambahkan animasi kustom
Jika Anda ingin menambahkan efek animasi kustom di luar animasi masuk dan keluar
bawaan, akses instance Transition
dasar melalui properti
transition
di dalam lambda konten untuk AnimatedVisibility
. Semua status
animasi yang ditambahkan ke instance Transition akan berjalan bersamaan dengan animasi
masuk dan keluar dari AnimatedVisibility
. AnimatedVisibility
menunggu hingga
semua animasi di Transition
selesai sebelum menghapus kontennya.
Untuk animasi keluar yang dibuat terpisah dari Transition
(seperti menggunakan
animate*AsState
), AnimatedVisibility
tidak akan dapat memperhitungkannya,
dan oleh karena itu dapat menghapus composable konten sebelum selesai.
var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn(), exit = fadeOut() ) { // this: AnimatedVisibilityScope // Use AnimatedVisibilityScope#transition to add a custom animation // to the AnimatedVisibility. val background by transition.animateColor(label = "color") { state -> if (state == EnterExitState.Visible) Color.Blue else Color.Gray } Box(modifier = Modifier.size(128.dp).background(background)) }
Lihat updateTransition untuk mengetahui detail tentang Transition
.
Menganimasikan berdasarkan status target dengan AnimatedContent
Composable AnimatedContent
akan menganimasikan kontennya saat composable tersebut berubah berdasarkan
status target.
Row { var count by remember { mutableStateOf(0) } Button(onClick = { count++ }) { Text("Add") } AnimatedContent(targetState = count) { targetCount -> // Make sure to use `targetCount`, not `count`. Text(text = "Count: $targetCount") } }
Perhatikan bahwa Anda harus selalu menggunakan parameter lambda dan mencerminkannya ke konten. API menggunakan nilai ini sebagai kunci untuk mengidentifikasi konten yang saat ini ditampilkan.
Secara default, konten awal akan memudar, lalu konten target akan makin jelas
(perilaku ini disebut memudar). Anda
dapat menyesuaikan perilaku animasi ini dengan menentukan objek ContentTransform
ke
parameter transitionSpec
. Anda dapat membuat ContentTransform
dengan mengombinasikan
EnterTransition
dan ExitTransition
menggunakan fungsi infix with
. Anda dapat menerapkan SizeTransform
ke ContentTransform
dengan melampirkannya dengan
fungsi infix using
.
AnimatedContent( targetState = count, transitionSpec = { // Compare the incoming number with the previous number. if (targetState > initialState) { // If the target number is larger, it slides up and fades in // while the initial (smaller) number slides up and fades out. slideInVertically { height -> height } + fadeIn() with slideOutVertically { height -> -height } + fadeOut() } else { // If the target number is smaller, it slides down and fades in // while the initial number slides down and fades out. slideInVertically { height -> -height } + fadeIn() with slideOutVertically { height -> height } + fadeOut() }.using( // Disable clipping since the faded slide-in/out should // be displayed out of bounds. SizeTransform(clip = false) ) } ) { targetCount -> Text(text = "$targetCount") }
EnterTransition
akan menentukan cara konten target akan muncul, dan
ExitTransition
akan menentukan cara konten awal akan menghilang. Selain
semua fungsi EnterTransition
dan ExitTransition
yang tersedia untuk
AnimatedVisibility
, AnimatedContent
menawarkan slideIntoContainer
dan slideOutOfContainer
.
Fungsi ini merupakan alternatif yang praktis untuk slideInHorizontally/Vertically
dan
slideOutHorizontally/Vertically
yang menghitung jarak slide berdasarkan pada
ukuran konten awal dan konten target dari
konten AnimatedContent
.
SizeTransform
menentukan cara
ukuran akan dianimasikan antara konten awal dan target. Anda memiliki
akses ke ukuran awal dan ukuran target saat membuat
animasi. SizeTransform
juga mengontrol apakah konten harus dipotong
ke ukuran komponen selama animasi.
var expanded by remember { mutableStateOf(false) } Surface( color = MaterialTheme.colorScheme.primary, onClick = { expanded = !expanded } ) { AnimatedContent( targetState = expanded, transitionSpec = { fadeIn(animationSpec = tween(150, 150)) with fadeOut(animationSpec = tween(150)) using SizeTransform { initialSize, targetSize -> if (targetState) { keyframes { // Expand horizontally first. IntSize(targetSize.width, initialSize.height) at 150 durationMillis = 300 } } else { keyframes { // Shrink vertically first. IntSize(initialSize.width, targetSize.height) at 150 durationMillis = 300 } } } } ) { targetExpanded -> if (targetExpanded) { Expanded() } else { ContentIcon() } } }
Menganimasikan transisi masuk dan keluar turunan
Sama seperti AnimatedVisibility
, pengubah animateEnterExit
tersedia di dalam lambda konten AnimatedContent
. Gunakan ini
untuk menerapkan EnterAnimation
dan ExitAnimation
ke setiap turunan langsung atau tidak langsung
secara terpisah.
Menambahkan animasi kustom
Sama seperti AnimatedVisibility
, kolom transition
tersedia di dalam
lambda konten AnimatedContent
. Gunakan ini untuk membuat efek animasi
kustom yang berjalan secara bersamaan dengan transisi AnimatedContent
. Lihat
updateTransition untuk mengetahui detailnya.
Menganimasikan antara dua tata letak dengan Crossfade
Crossfade
membuat animasi di antara dua tata letak dengan animasi crossfade. Dengan mengganti nilai yang diteruskan ke parameter current
, konten dialihkan dengan animasi crossfade.
var currentPage by remember { mutableStateOf("A") } Crossfade(targetState = currentPage) { screen -> when (screen) { "A" -> Text("Page A") "B" -> Text("Page B") } }
Pengubah animasi bawaan
Menganimasikan perubahan ukuran composable dengan animateContentSize
![Composable hijau yang menganimasikan perubahan ukurannya dengan lancar.](https://developer.android.com/static/develop/ui/compose/images/animations/animated_content_size.gif?authuser=19&hl=id)
Pengubah animateContentSize
menganimasikan perubahan ukuran.
var expanded by remember { mutableStateOf(false) } Box( modifier = Modifier .background(colorBlue) .animateContentSize() .height(if (expanded) 400.dp else 200.dp) .fillMaxWidth() .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { expanded = !expanded } ) { }
Animasi item daftar
Jika Anda ingin menganimasikan pengurutan ulang item di dalam daftar atau petak Lambat, lihat dokumentasi animasi item tata letak Lambat.
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Animasi berbasis nilai
- Animasi di Compose
- Dukungan alat animasi {:#tooling}