คอมโพเนนต์ SwipeToDismissBox ช่วยให้ผู้ใช้ปิดหรืออัปเดตรายการได้โดยการปัดไปทางซ้ายหรือขวา
แพลตฟอร์ม API
ใช้ Composable 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จัดการสถานะคอมโพเนนต์ ซึ่งจะทริกเกอร์ CallbackconfirmValueChangeเมื่อการโต้ตอบกับรายการเสร็จสิ้น เนื้อหา Callback จะจัดการการดำเนินการต่างๆ ที่เป็นไปได้ Callback จะแสดงผลบูลีนที่บอกคอมโพเนนต์ว่าควรแสดงภาพเคลื่อนไหวการปิดหรือไม่ ในกรณีนี้- หากปัดรายการตั้งแต่ต้นจนจบ ระบบจะเรียกใช้แลมบ์ดา
onToggleDoneโดยส่ง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ได้ เมื่อมีการเพิ่มหรือนำรายการออกจากลิสต์นี้ Compose จะจัดองค์ประกอบส่วนต่างๆ ของ UI ที่ขึ้นอยู่กับลิสต์นั้นใหม่- ภายใน
mutableStateListOf()มีการเริ่มต้นออบเจ็กต์TodoItem4 รายการพร้อมคำอธิบายที่เกี่ยวข้อง ได้แก่ "จ่ายบิล" "ซื้อของใช้" "ไปยิม" และ "กินข้าวเย็น"
- ภายใน
LazyColumnแสดงรายการtodoItemsที่เลื่อนในแนวตั้งonToggleDone = { todoItem -> ... }เป็นฟังก์ชัน Callback ที่เรียกใช้จากภายใน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จะวาดลงใน Canvas โดยตรงด้านหลังเนื้อหาของ ComposableIcondrawRect()จะวาดสี่เหลี่ยมผืนผ้าบน Canvas และเติมขอบเขตทั้งหมดของขอบเขตการวาดด้วย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