Thành phần SwipeToDismissBox
cho phép người dùng đóng hoặc cập nhật một mục bằng cách vuốt mục đó sang trái hoặc phải.
Nền tảng API
Sử dụng thành phần kết hợp SwipeToDismissBox
để triển khai các thao tác được kích hoạt bằng cử chỉ vuốt. Các tham số chính bao gồm:
state
: Trạng tháiSwipeToDismissBoxState
được tạo để lưu trữ giá trị do các phép tính trên mục vuốt tạo ra, từ đó kích hoạt các sự kiện khi được tạo.backgroundContent
: Một thành phần kết hợp có thể tuỳ chỉnh hiển thị phía sau nội dung mục được hiển thị khi nội dung được vuốt.
Ví dụ cơ bản: Cập nhật hoặc đóng khi vuốt
Các đoạn mã trong ví dụ này cho thấy cách triển khai thao tác vuốt để cập nhật mục khi vuốt từ đầu đến cuối hoặc đóng mục khi vuốt từ cuối đến đầu.
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( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.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( imageVector = Icons.Default.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.") } ) } }
Các điểm chính về mã
swipeToDismissBoxState
quản lý trạng thái thành phần. Phương thức này sẽ kích hoạt lệnh gọi lạiconfirmValueChange
sau khi tương tác với mục đó. Phần nội dung lệnh gọi lại xử lý các thao tác có thể thực hiện. Lệnh gọi lại trả về một boolean cho thành phần biết liệu thành phần đó có hiển thị ảnh động đóng hay không. Trong trường hợp này:- Nếu bạn vuốt mục từ đầu đến cuối, thì thao tác này sẽ gọi lambda
onToggleDone
, truyềntodoItem
hiện tại. Thao tác này tương ứng với việc cập nhật mục cần làm. - Nếu bạn vuốt mục từ cuối đến đầu, thì thao tác này sẽ gọi hàm lambda
onRemove
, truyềntodoItem
hiện tại. Điều này tương ứng với việc xoá mục cần làm. it != StartToEnd
: Dòng này trả vềtrue
nếu hướng vuốt không phải làStartToEnd
vàfalse
nếu không. Việc trả vềfalse
sẽ ngănSwipeToDismissBox
biến mất ngay sau khi vuốt "đã bật/tắt", cho phép xác nhận bằng hình ảnh hoặc ảnh động.
- Nếu bạn vuốt mục từ đầu đến cuối, thì thao tác này sẽ gọi lambda
SwipeToDismissBox
cho phép tương tác vuốt theo chiều ngang trên từng mục. Ở trạng thái nghỉ, thành phần này hiển thị nội dung bên trong của thành phần, nhưng khi người dùng bắt đầu vuốt, nội dung sẽ được di chuyển ra xa vàbackgroundContent
sẽ xuất hiện. Cả nội dung thông thường vàbackgroundContent
đều nhận được các quy tắc ràng buộc đầy đủ của vùng chứa mẹ để hiển thị chính nội dung đó.content
được vẽ trênbackgroundContent
. Trong trường hợp này:backgroundContent
được triển khai dưới dạngIcon
có màu nền dựa trênSwipeToDismissBoxValue
:Blue
khi vuốtStartToEnd
– bật/tắt một việc cần làm.Red
khi vuốtEndToStart
– xoá một việc cần làm.- Không có gì hiển thị ở chế độ nền cho
Settled
– khi mục không được vuốt, không có gì hiển thị ở chế độ nền. - Tương tự,
Icon
hiển thị sẽ điều chỉnh theo hướng vuốt: StartToEnd
hiển thị biểu tượngCheckBox
khi việc cần làm đã hoàn tất và biểu tượngCheckBoxOutlineBlank
khi việc cần làm chưa hoàn tất.EndToStart
hiển thị biểu tượngDelete
.
@Composable private 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() ) } } }
Các điểm chính về mã
mutableStateListOf(...)
tạo một danh sách có thể quan sát có thể chứa các đối tượngTodoItem
. Khi một mục được thêm hoặc xoá khỏi danh sách này, Compose sẽ kết hợp lại các phần của giao diện người dùng phụ thuộc vào mục đó.- Bên trong
mutableStateListOf()
, 4 đối tượngTodoItem
được khởi tạo với nội dung mô tả tương ứng: "Thanh toán hoá đơn", "Mua đồ ăn", "Đi tập thể dục" và "Ăn tối".
- Bên trong
LazyColumn
hiển thị danh sáchtodoItems
cuộn theo chiều dọc.onToggleDone = { todoItem -> ... }
là một hàm gọi lại được gọi từ trongTodoListItem
khi người dùng đánh dấu một đối tượng là đã hoàn tất. Phương thức này cập nhật thuộc tínhisItemDone
củatodoItem
. VìtodoItems
là mộtmutableStateListOf
, nên thay đổi này sẽ kích hoạt quá trình kết hợp lại, cập nhật giao diện người dùng.onRemove = { todoItem -> ... }
là một hàm gọi lại được kích hoạt khi người dùng xoá mục. Thao tác này sẽ xoátodoItem
cụ thể khỏi danh sáchtodoItems
. Điều này cũng gây ra quá trình kết hợp lại và mục sẽ bị xoá khỏi danh sách hiển thị.- Đối tượng sửa đổi
animateItem
được áp dụng cho mỗiTodoListItem
đểplacementSpec
của đối tượng sửa đổi được gọi khi mục đã bị loại bỏ. Thao tác này sẽ tạo ảnh động cho việc xoá mục, cũng như sắp xếp lại các mục khác trong danh sách.
Kết quả
Video sau đây minh hoạ chức năng vuốt để đóng cơ bản từ các đoạn mã trước:
Hãy xem tệp nguồn GitHub để biết toàn bộ mã mẫu.
Ví dụ nâng cao: Tạo ảnh động cho màu nền khi vuốt
Các đoạn mã sau đây cho biết cách kết hợp ngưỡng vị trí để tạo ảnh động cho màu nền của một mục khi vuốt.
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( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.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( imageVector = Icons.Default.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.") } ) } } }
Các điểm chính về mã
drawBehind
vẽ trực tiếp vào canvas phía sau nội dung của thành phần kết hợpIcon
.drawRect()
vẽ một hình chữ nhật trên canvas và lấp đầy toàn bộ ranh giới của phạm vi vẽ bằngColor
đã chỉ định.
- Khi vuốt, màu nền của mục sẽ chuyển đổi suôn sẻ bằng cách sử dụng
lerp
.- Khi vuốt từ
StartToEnd
, màu nền sẽ thay đổi dần từ màu xám nhạt sang màu xanh dương. - Khi vuốt từ
EndToStart
, màu nền sẽ thay đổi dần từ màu xám nhạt sang màu đỏ. - Mức độ chuyển đổi từ màu này sang màu khác được xác định bằng
swipeToDismissBoxState.progress
.
- Khi vuốt từ
OutlinedCard
tạo ra một sự phân tách hình ảnh tinh tế giữa các mục trong danh sách.
@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() ) } } }
Các điểm chính về mã
- Để biết các điểm chính về mã này, hãy xem phần Các điểm chính trong phần trước. Phần này mô tả một đoạn mã giống hệt.
Kết quả
Video sau đây cho thấy chức năng nâng cao với màu nền động:
Hãy xem tệp nguồn GitHub để biết toàn bộ mã mẫu.