Komponen SwipeToDismissBox memungkinkan pengguna menutup atau memperbarui
item dengan menggesernya ke kiri atau kanan.
Platform API
Gunakan composable SwipeToDismissBox untuk menerapkan tindakan yang dipicu
oleh gestur geser. Parameter utama mencakup:
state: StatusSwipeToDismissBoxStateyang dibuat untuk menyimpan nilai yang dihasilkan oleh penghitungan pada item geser, yang memicu peristiwa saat dihasilkan.backgroundContent: Composable yang dapat disesuaikan yang ditampilkan di belakang konten item yang ditampilkan saat konten digeser.
Contoh dasar: Memperbarui atau menutup saat digeser
Cuplikan dalam contoh ini menunjukkan implementasi geser yang memperbarui item saat digeser dari awal ke akhir, atau menutup item saat digeser dari akhir ke awal.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItem( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( painter = rememberVectorPainter(if (todoItem.isItemDone) AppIcons.CheckBox else AppIcons.CheckBoxOutlineBlank), contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .background(Color.Blue) .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( painter = rememberVectorPainter(AppIcons.Delete), contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(Color.Red) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } }
Poin penting tentang kode
swipeToDismissBoxStatemengelola status komponen. Callback ini akan memicu callbackconfirmValueChangesetelah interaksi dengan item selesai. Isi callback menangani berbagai kemungkinan tindakan. Callback menampilkan boolean yang memberi tahu komponen apakah harus menampilkan animasi tutup. Dalam hal ini:- Jika item digeser dari awal hingga akhir, item tersebut akan memanggil lambda
onToggleDone, yang meneruskantodoItemsaat ini. Hal ini sesuai dengan memperbarui item daftar tugas. - Jika item digeser dari akhir ke awal, item tersebut akan memanggil lambda
onRemove, dengan meneruskantodoItemsaat ini. Tindakan ini sesuai dengan penghapusan item tugas. it != StartToEnd: Baris ini menampilkantruejika arah geser bukanStartToEnd, danfalsejika sebaliknya. Menampilkanfalseakan mencegahSwipeToDismissBoxlangsung menghilang setelah geser "tombol selesai", sehingga memungkinkan konfirmasi visual atau animasi.
- Jika item digeser dari awal hingga akhir, item tersebut akan memanggil lambda
SwipeToDismissBoxmemungkinkan interaksi geser horizontal pada setiap item. Saat tidak digunakan, komponen ini menampilkan konten bagian dalam, tetapi saat pengguna mulai menggeser, konten akan dipindahkan danbackgroundContentakan muncul. Konten normal danbackgroundContentmendapatkan batasan penuh dari penampung induk untuk merender dirinya sendiri.contentdigambar di atasbackgroundContent. Dalam hal ini:backgroundContentdiimplementasikan sebagaiIcondengan warna latar belakang berdasarkanSwipeToDismissBoxValue:Bluesaat menggeserStartToEnd— mengalihkan item tugas.Redsaat menggeserEndToStart— menghapus item daftar tugas.- Tidak ada yang ditampilkan di latar belakang untuk
Settled— saat item tidak digeser, tidak ada yang ditampilkan di latar belakang. - Demikian pula,
Iconyang ditampilkan akan menyesuaikan dengan arah geser: StartToEndmenampilkan ikonCheckBoxsaat item daftar tugas selesai dan ikonCheckBoxOutlineBlanksaat belum selesai.EndToStartmenampilkan ikonDelete.
@Composable fun SwipeItemExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItem( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
Poin penting tentang kode
mutableStateListOf(...)membuat daftar yang dapat diamati yang dapat menyimpan objekTodoItem. Saat item ditambahkan atau dihapus dari daftar ini, Compose akan merekomposisi bagian UI yang bergantung padanya.- Di dalam
mutableStateListOf(), empat objekTodoItemdiinisialisasi dengan deskripsinya masing-masing: "Bayar tagihan", "Beli bahan makanan", "Pergi ke gym", dan "Makan malam".
- Di dalam
LazyColumnmenampilkan daftar scroll vertikaltodoItems.onToggleDone = { todoItem -> ... }adalah fungsi callback yang dipanggil dari dalamTodoListItemsaat pengguna menandai objek sebagai selesai. Metode ini memperbarui propertiisItemDonedaritodoItem. KarenatodoItemsadalahmutableStateListOf, perubahan ini memicu rekomposisi, yang mengupdate UI.onRemove = { todoItem -> ... }adalah fungsi callback yang dipicu saat pengguna menghapus item. Tindakan ini akan menghapustodoItemtertentu dari daftartodoItems. Hal ini juga menyebabkan rekomposisi, dan item akan dihapus dari daftar yang ditampilkan.- Pengubah
animateItemditerapkan ke setiapTodoListItemsehinggaplacementSpecpengubah dipanggil saat item telah ditutup. Tindakan ini menganimasikan penghapusan item, serta pengurutan ulang item lain dalam daftar.
Hasil
Video berikut menunjukkan fungsi geser untuk menutup dasar dari cuplikan sebelumnya:
Lihat file sumber GitHub untuk mengetahui kode contoh lengkapnya.
Contoh lanjutan: Menganimasikan warna latar belakang saat menggeser
Cuplikan berikut menunjukkan cara menggabungkan nilai minimum posisi untuk menganimasikan warna latar belakang item saat digeser.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItemWithAnimation( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( painter = rememberVectorPainter(if (todoItem.isItemDone) AppIcons.CheckBox else AppIcons.CheckBoxOutlineBlank), contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .drawBehind { drawRect(lerp(Color.LightGray, Color.Blue, swipeToDismissBoxState.progress)) } .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( painter = rememberVectorPainter(AppIcons.Delete), contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(lerp(Color.LightGray, Color.Red, swipeToDismissBoxState.progress)) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { OutlinedCard(shape = RectangleShape) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } } }
Poin penting tentang kode
drawBehindmenggambar langsung ke kanvas di belakang konten composableIcon.drawRect()menggambar persegi panjang di kanvas dan mengisi seluruh batas cakupan gambar denganColoryang ditentukan.
- Saat menggeser, warna latar belakang item akan bertransisi dengan lancar menggunakan
lerp.- Untuk geser dari
StartToEnd, warna latar belakang berubah secara bertahap dari abu-abu muda menjadi biru. - Untuk geser dari
EndToStart, warna latar belakang berubah secara bertahap dari abu-abu muda menjadi merah. - Jumlah transisi dari satu warna ke warna berikutnya ditentukan oleh
swipeToDismissBoxState.progress.
- Untuk geser dari
OutlinedCardmenambahkan pemisahan visual yang halus di antara item daftar.
@Composable private fun SwipeItemWithAnimationExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItemWithAnimation( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
Poin penting tentang kode
- Untuk poin-poin penting tentang kode ini, lihat Poin-poin penting dari bagian sebelumnya, yang menjelaskan cuplikan kode yang identik.
Hasil
Video berikut menunjukkan fungsi lanjutan dengan warna latar belakang animasi:
Lihat file sumber GitHub untuk mengetahui kode contoh lengkapnya.