คอมโพเนนต์ SwipeToDismissBox
ช่วยให้ผู้ใช้ปิดหรืออัปเดตรายการได้ด้วยการปัดไปทางซ้ายหรือขวา
แพลตฟอร์ม API
ใช้คอมโพสิเบิล SwipeToDismissBox
เพื่อใช้การดำเนินการที่เรียกให้แสดงโดยท่าทางสัมผัสด้วยการปัด พารามิเตอร์หลักๆ มีดังนี้
state
: สถานะSwipeToDismissBoxState
ที่สร้างขึ้นเพื่อจัดเก็บค่าที่เกิดจากการคํานวณในรายการการปัด ซึ่งจะทริกเกอร์เหตุการณ์เมื่อสร้างขึ้นbackgroundContent
: Composable ที่ปรับแต่งได้ซึ่งแสดงอยู่หลังรายการ เนื้อหาที่จะแสดงเมื่อมีการปัดเนื้อหา
ตัวอย่างพื้นฐาน: อัปเดตหรือปิดเมื่อปัด
ตัวอย่างนี้คือการใช้การปัดที่อัปเดตรายการเมื่อปัดจากต้นไปสิ้นสุด หรือปิดรายการเมื่อปัดจากสิ้นสุดไปต้น
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.") } ) } }
ประเด็นสำคัญเกี่ยวกับรหัส
swipeToDismissBoxState
จัดการสถานะคอมโพเนนต์ ซึ่งจะทริกเกอร์การเรียกกลับconfirmValueChange
เมื่อการโต้ตอบกับรายการเสร็จสิ้น เนื้อหาของคอลแบ็กจะจัดการการดำเนินการต่างๆ ที่เป็นไปได้ ฟังก์ชันการเรียกกลับจะแสดงผลเป็นค่าบูลีนซึ่งบอกคอมโพเนนต์ว่าควรแสดงภาพเคลื่อนไหวการปิดหรือไม่ ในกรณีนี้- หากปัดรายการจากต้นจนจบ ระบบจะเรียกใช้
onToggleDone
lambda โดยส่งtodoItem
ปัจจุบัน ซึ่งสอดคล้องกับการอัปเดตรายการสิ่งที่ต้องทำ - หากปัดรายการจากท้ายไปต้น ระบบจะเรียกใช้ Lambda
onRemove
โดยส่งtodoItem
ปัจจุบัน ซึ่งสอดคล้องกับการลบรายการที่ต้องทำ it != StartToEnd
: บรรทัดนี้จะแสดงผลtrue
หากทิศทางการปัดไม่ใช่StartToEnd
และแสดงผลfalse
ในกรณีอื่นๆfalse
ที่กลับมาจะป้องกันไม่ให้SwipeToDismissBox
หายไปทันทีหลังจากการปัด "สลับเสร็จแล้ว" ซึ่งช่วยให้เห็นภาพยืนยันหรือภาพเคลื่อนไหว
- หากปัดรายการจากต้นจนจบ ระบบจะเรียกใช้
SwipeToDismissBox
เปิดใช้การโต้ตอบด้วยการปัดแนวนอนในแต่ละรายการ เมื่ออยู่ในสถานะ "พัก" ไอคอนจะแสดงเนื้อหาภายในของคอมโพเนนต์ แต่เมื่อผู้ใช้เริ่มปัด เนื้อหาจะเลื่อนออกไปและbackgroundContent
จะปรากฏขึ้น ทั้งเนื้อหาปกติและbackgroundContent
จะได้รับข้อจำกัดทั้งหมดของคอนเทนเนอร์หลักเพื่อแสดงผลcontent
วาดอยู่ด้านบนของbackgroundContent
ในกรณีนี้backgroundContent
ติดตั้งใช้งานเป็นIcon
ที่มีสีพื้นหลังตามSwipeToDismissBoxValue
ดังนี้Blue
เมื่อปัดStartToEnd
- สลับรายการสิ่งที่ต้องทำRed
เมื่อปัดEndToStart
- ลบรายการสิ่งที่ต้องทํา- ไม่มีสิ่งใดแสดงในเบื้องหลังสำหรับ
Settled
— เมื่อไม่ได้ปัดรายการ ระบบจะไม่แสดงสิ่งใดในเบื้องหลัง - ในทำนองเดียวกัน
Icon
ที่แสดงจะปรับตามทิศทางการปัด StartToEnd
จะแสดงไอคอนCheckBox
เมื่องานในรายการสิ่งที่ต้องทำเสร็จแล้ว และไอคอนCheckBoxOutlineBlank
เมื่องานยังไม่เสร็จEndToStart
แสดงไอคอนDelete
@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() ) } } }
ประเด็นสำคัญเกี่ยวกับรหัส
mutableStateListOf(...)
สร้างลิสต์ที่สังเกตได้ซึ่งเก็บออบเจ็กต์TodoItem
ได้ เมื่อมีการเพิ่มหรือนำรายการออกจากรายการนี้ คอมโพซจะจัดเรียงองค์ประกอบ UI ที่ขึ้นอยู่กับรายการนั้นใหม่- ภายใน
mutableStateListOf()
ระบบจะเริ่มต้นออบเจ็กต์TodoItem
4 รายการพร้อมคำอธิบายที่เกี่ยวข้อง ได้แก่ "จ่ายบิล" "ซื้อของใช้ทั่วไป" "ไปฟิตเนส" และ "ทานอาหารเย็น"
- ภายใน
LazyColumn
แสดงรายการtodoItems
แบบเลื่อนในแนวตั้งonToggleDone = { todoItem -> ... }
คือฟังก์ชันการเรียกกลับที่เรียกจากภายในTodoListItem
เมื่อผู้ใช้ทำเครื่องหมายวัตถุว่าเสร็จแล้ว โดยจะอัปเดตพร็อพเพอร์ตี้isItemDone
ของtodoItem
เนื่องจากtodoItems
เป็นmutableStateListOf
การเปลี่ยนแปลงนี้จึงทริกเกอร์การจัดองค์ประกอบใหม่เพื่ออัปเดต UIonRemove = { todoItem -> ... }
คือฟังก์ชัน Callback ที่ทริกเกอร์เมื่อผู้ใช้นำรายการออก ซึ่งจะนำtodoItem
ที่เฉพาะเจาะจงออกจากรายการtodoItems
ซึ่งจะทําให้เกิดการจัดองค์ประกอบใหม่ด้วย และระบบจะนำรายการออกจากรายการที่แสดง- ระบบจะใช้ตัวแก้ไข
animateItem
กับTodoListItem
แต่ละรายการเพื่อให้ระบบเรียกplacementSpec
ของตัวแก้ไขเมื่อมีการปิดรายการ ซึ่งจะแสดงภาพการนำรายการออก รวมถึงการจัดเรียงรายการอื่นๆ ในรายการใหม่
ผลลัพธ์
วิดีโอต่อไปนี้แสดงฟังก์ชันการปัดเพื่อปิดพื้นฐานจากตัวอย่างข้อมูลก่อนหน้า
ดูโค้ดตัวอย่างแบบเต็มได้ที่ไฟล์ซอร์ส GitHub
ตัวอย่างขั้นสูง: แสดงสีพื้นหลังเป็นภาพเคลื่อนไหวเมื่อปัด
ข้อมูลโค้ดต่อไปนี้แสดงวิธีใช้เกณฑ์ตำแหน่งเพื่อทำให้สีพื้นหลังของรายการเคลื่อนไหวเมื่อปัด
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.") } ) } } }
ประเด็นสำคัญเกี่ยวกับรหัส
drawBehind
จะวาดลงในผืนผ้าใบโดยตรงหลังเนื้อหาของIcon
composabledrawRect()
วาดสี่เหลี่ยมผืนผ้าบนผืนผ้าและเติมColor
ที่ระบุไว้ทั่วทั้งขอบเขตการวาด
- เมื่อปัด พื้นหลังของรายการจะเปลี่ยนอย่างราบรื่นโดยใช้
lerp
- สำหรับการปัดจาก
StartToEnd
สีพื้นหลังจะค่อยๆ เปลี่ยนจากสีเทาอ่อนเป็นสีน้ำเงิน - สำหรับการปัดจาก
EndToStart
สีพื้นหลังจะค่อยๆ เปลี่ยนจากสีเทาอ่อนเป็นสีแดง - ปริมาณการเปลี่ยนจากสีหนึ่งไปยังอีกสีหนึ่งจะกำหนดโดย
swipeToDismissBoxState.progress
- สำหรับการปัดจาก
OutlinedCard
เพิ่มการแยกภาพอย่างละเอียดระหว่างรายการในลิสต์
@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() ) } } }
ประเด็นสำคัญเกี่ยวกับรหัส
- ดูประเด็นสําคัญเกี่ยวกับโค้ดนี้ได้ที่ประเด็นสําคัญจากส่วนก่อนหน้า ซึ่งอธิบายข้อมูลโค้ดที่เหมือนกัน
ผลลัพธ์
วิดีโอต่อไปนี้แสดงฟังก์ชันขั้นสูงที่มีพื้นหลังเคลื่อนไหว
ดูโค้ดตัวอย่างแบบเต็มได้ที่ไฟล์ซอร์ส GitHub