มีคำศัพท์และแนวคิดหลายอย่างที่สำคัญต่อการทำความเข้าใจเมื่อทำงานเกี่ยวกับการจัดการท่าทางสัมผัสในแอปพลิเคชัน หน้านี้จะอธิบายคำว่าพอยเตอร์ เหตุการณ์พอยเตอร์ และท่าทางสัมผัส รวมถึงแนะนำระดับนามธรรมต่างๆ สำหรับท่าทางสัมผัส นอกจากนี้ยังเจาะลึกรายละเอียดเพิ่มเติมเกี่ยวกับการใช้และการเผยแพร่เหตุการณ์ด้วย
คำจำกัดความ
หากต้องการทำความเข้าใจแนวคิดต่างๆ ในหน้านี้ คุณต้องเข้าใจคำศัพท์บางคำที่ใช้ดังนี้
- ตัวชี้: วัตถุที่จับต้องได้ซึ่งคุณใช้โต้ตอบกับแอปพลิเคชันได้
สำหรับอุปกรณ์เคลื่อนที่ ตัวชี้ที่พบได้บ่อยที่สุดคือนิ้วของคุณที่โต้ตอบกับหน้าจอสัมผัส หรือจะใช้สไตลัสแทนนิ้วก็ได้
สำหรับหน้าจอขนาดใหญ่ คุณสามารถใช้เมาส์หรือแทร็กแพดเพื่อโต้ตอบกับจอแสดงผลโดยอ้อมได้ อุปกรณ์อินพุตต้องสามารถ "ชี้" ไปที่พิกัดเพื่อถือว่าเป็นตัวชี้ ดังนั้นแป้นพิมพ์จึงไม่ถือว่าเป็นตัวชี้ ใน Compose ประเภทตัวชี้จะรวมอยู่ในการเปลี่ยนแปลงตัวชี้โดยใช้
PointerType - เหตุการณ์ตัวชี้: อธิบายการโต้ตอบระดับต่ำของตัวชี้อย่างน้อย 1 ตัวกับแอปพลิเคชัน ณ เวลาหนึ่งๆ การโต้ตอบด้วยตัวชี้ เช่น การวางนิ้วบนหน้าจอหรือการลากเมาส์ จะทริกเกอร์เหตุการณ์ ใน Compose ข้อมูลที่เกี่ยวข้องทั้งหมดสำหรับเหตุการณ์ดังกล่าวจะอยู่ในคลาส
PointerEvent - ท่าทางสัมผัส: ลำดับของเหตุการณ์เคอร์เซอร์ที่ตีความได้ว่าเป็นการดำเนินการเดียว ตัวอย่างเช่น ท่าทางสัมผัสการแตะถือเป็นลำดับของเหตุการณ์การกดลงตามด้วยเหตุการณ์การยกขึ้น มีท่าทางสัมผัสทั่วไปที่แอปจำนวนมากใช้ เช่น แตะ ลาก หรือเปลี่ยนรูปแบบ แต่คุณก็สร้างท่าทางสัมผัสที่กำหนดเองได้เมื่อจำเป็น
ระดับต่างๆ ของการแยกส่วนข้อมูล
Jetpack Compose มีระดับนามธรรมที่แตกต่างกันสำหรับการจัดการท่าทางสัมผัส
ระดับบนสุดคือการรองรับคอมโพเนนต์ คอมโพสิเบิลอย่าง Button จะรวมการรองรับท่าทางสัมผัสโดยอัตโนมัติ หากต้องการเพิ่มการรองรับท่าทางสัมผัสให้กับคอมโพเนนต์ที่กำหนดเอง คุณสามารถเพิ่มตัวปรับแต่งท่าทางสัมผัส เช่น clickable ลงใน Composable ใดก็ได้ สุดท้าย หากต้องการท่าทางสัมผัสที่กำหนดเอง คุณสามารถใช้ตัวปรับแต่ง pointerInput ได้
ตามกฎแล้ว ให้สร้างในระดับ Abstraction สูงสุดที่มีฟังก์ชันการทำงานที่คุณต้องการ วิธีนี้จะช่วยให้คุณได้รับประโยชน์จากแนวทางปฏิบัติแนะนำที่รวมอยู่ในเลเยอร์ ตัวอย่างเช่น Button มีข้อมูลเชิงความหมายมากกว่า ซึ่งใช้สำหรับการช่วยเหลือพิเศษ มากกว่า clickable ซึ่งมีข้อมูลมากกว่าการใช้งาน pointerInput แบบดิบ
การสนับสนุนคอมโพเนนต์
คอมโพเนนต์ที่พร้อมใช้งานทันทีจำนวนมากใน Compose มีการจัดการท่าทางสัมผัสภายในบางประเภท ตัวอย่างเช่น LazyColumn จะตอบสนองต่อท่าทางการลากด้วยการเลื่อนเนื้อหา Button จะแสดงเอฟเฟกต์ริปเปิลเมื่อคุณกด และคอมโพเนนต์ SwipeToDismiss จะมีตรรกะการปัดเพื่อปิดองค์ประกอบ การจัดการท่าทางสัมผัสประเภทนี้จะทำงานโดยอัตโนมัติ
นอกจากการจัดการท่าทางสัมผัสภายในแล้ว คอมโพเนนต์จำนวนมากยังกำหนดให้ผู้เรียกจัดการท่าทางสัมผัสด้วย เช่น Button จะตรวจจับการแตะและทริกเกอร์กิจกรรมการคลิกโดยอัตโนมัติ คุณส่ง Lambda onClick ไปยัง Button เพื่อตอบสนองต่อท่าทางสัมผัส ในทำนองเดียวกัน คุณเพิ่ม onValueChange lambda ลงใน Slider เพื่อตอบสนองต่อผู้ใช้ที่ลากแฮนเดิลแถบเลื่อน
เมื่อเหมาะกับ Use Case ของคุณ ให้เลือกใช้ท่าทางสัมผัสที่รวมอยู่ในคอมโพเนนต์ เนื่องจากมีการรองรับโฟกัสและการช่วยเหลือพิเศษที่พร้อมใช้งานทันที และได้รับการทดสอบมาเป็นอย่างดี เช่น Button จะมีการทำเครื่องหมายด้วยวิธีพิเศษเพื่อให้บริการการช่วยเหลือพิเศษอธิบายได้อย่างถูกต้องว่าเป็นปุ่ม แทนที่จะเป็นเพียงองค์ประกอบที่คลิกได้
// Talkback: "Click me!, Button, double tap to activate" Button(onClick = { /* TODO */ }) { Text("Click me!") } // Talkback: "Click me!, double tap to activate" Box(Modifier.clickable { /* TODO */ }) { Text("Click me!") }
ดูข้อมูลเพิ่มเติมเกี่ยวกับการช่วยเหลือพิเศษใน Compose ได้ที่การช่วยเหลือพิเศษใน Compose
เพิ่มท่าทางสัมผัสที่เฉพาะเจาะจงลงใน Composable ที่กำหนดเองด้วยตัวแก้ไข
คุณสามารถใช้ตัวปรับแต่งท่าทางสัมผัสกับ Composable ใดก็ได้เพื่อให้ Composable ฟังท่าทางสัมผัส เช่น คุณสามารถอนุญาตให้ Box ทั่วไปจัดการท่าทางการแตะโดยทำให้เป็น clickable หรืออนุญาตให้ Column จัดการการเลื่อนแนวตั้งโดยใช้ verticalScroll
มีตัวแก้ไขหลายตัวสำหรับจัดการท่าทางสัมผัสประเภทต่างๆ ดังนี้
- จัดการการแตะและการกดด้วยตัวแก้ไข
clickable,combinedClickable,selectable,toggleableและtriStateToggleable - จัดการการเลื่อนด้วยตัวแก้ไข
horizontalScroll,verticalScrollและscrollableที่ใช้กันทั่วไป - จัดการการลากด้วยตัวปรับแต่ง
draggableและswipeable - จัดการท่าทางสัมผัสแบบมัลติทัช เช่น การเลื่อน การหมุน และการซูม ด้วยตัวปรับแต่ง
transformable
ตามกฎแล้ว ให้เลือกใช้ตัวแก้ไขท่าทางสัมผัสที่พร้อมใช้งานทันทีมากกว่าการจัดการท่าทางสัมผัสที่กำหนดเอง
ตัวแก้ไขจะเพิ่มฟังก์ชันการทำงานเพิ่มเติมจากการจัดการเหตุการณ์ตัวชี้แบบล้วนๆ
ตัวอย่างเช่น ตัวแก้ไข clickable ไม่เพียงเพิ่มการตรวจจับการกดและการแตะเท่านั้น แต่ยังเพิ่มข้อมูลเชิงความหมาย การบ่งชี้ภาพในการโต้ตอบ การวางเมาส์เหนือ การโฟกัส และการรองรับแป้นพิมพ์ด้วย คุณสามารถตรวจสอบซอร์สโค้ดของ clickable เพื่อดูวิธีเพิ่มฟังก์ชันการทำงานได้
เพิ่มท่าทางสัมผัสที่กำหนดเองไปยัง Composable ใดก็ได้ด้วยตัวแก้ไข pointerInput
ท่าทางสัมผัสบางอย่างไม่ได้ใช้ตัวปรับแต่งท่าทางสัมผัสที่พร้อมใช้งานทันที ตัวอย่างเช่น คุณไม่สามารถใช้ตัวปรับแต่งเพื่อตอบสนองต่อการลากหลังจากกดค้าง การกดปุ่ม Control ค้างไว้แล้วคลิก หรือการแตะด้วย 3 นิ้ว แต่คุณสามารถเขียนตัวแฮนเดิลท่าทางสัมผัสของคุณเองเพื่อระบุท่าทางสัมผัสที่กำหนดเองเหล่านี้ได้ คุณสามารถสร้างตัวแฮนเดิลท่าทางสัมผัสได้ด้วยตัวแก้ไข pointerInput ซึ่งช่วยให้คุณเข้าถึงเหตุการณ์ตัวชี้ข้อมูลดิบได้
โค้ดต่อไปนี้จะรอรับเหตุการณ์ตัวชี้ข้อมูลดิบ
@Composable private fun LogPointerEvents(filter: PointerEventType? = null) { var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(filter) { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() // handle pointer event if (filter == null || event.type == filter) { log = "${event.type}, ${event.changes.first().position}" } } } } ) } }
หากคุณแยกข้อมูลโค้ดนี้ องค์ประกอบหลักจะมีดังนี้
- ตัวแก้ไข
pointerInputคุณส่งคีย์อย่างน้อย 1 รายการให้เมธอด เมื่อค่าของคีย์ใดคีย์หนึ่งเปลี่ยนแปลง ระบบจะเรียกใช้ Lambda ของเนื้อหาตัวแก้ไขอีกครั้ง ตัวอย่างจะส่งตัวกรองที่ไม่บังคับไปยัง Composable หากค่าของตัวกรองนั้นเปลี่ยนแปลง ควรเรียกใช้ตัวแฮนเดิลเหตุการณ์ตัวชี้อีกครั้งเพื่อให้แน่ใจว่าระบบบันทึกเหตุการณ์ที่ถูกต้อง awaitPointerEventScopeสร้างขอบเขตโครูทีนที่ใช้รอเหตุการณ์เคอร์เซอร์ได้awaitPointerEventจะระงับโครูทีนจนกว่าจะเกิดเหตุการณ์ตัวชี้ถัดไป
แม้ว่าการฟังเหตุการณ์อินพุตดิบจะมีประสิทธิภาพ แต่ก็มีความซับซ้อนในการเขียนท่าทางสัมผัสที่กำหนดเองโดยอิงตามข้อมูลดิบนี้ มีเมธอดของยูทิลิตีมากมายที่ช่วยให้สร้างท่าทางสัมผัสที่กำหนดเองได้ง่ายขึ้น
ตรวจจับท่าทางสัมผัสแบบเต็ม
คุณสามารถรอให้เกิดท่าทางสัมผัสที่เฉพาะเจาะจงและตอบสนองอย่างเหมาะสม แทนที่จะจัดการเหตุการณ์ตัวชี้ดิบ AwaitPointerEventScope มีเมธอดสำหรับการฟังเหตุการณ์ต่อไปนี้
- กด แตะ แตะสองครั้ง และกดค้าง:
detectTapGestures - ลาก:
detectHorizontalDragGestures,detectVerticalDragGestures,detectDragGesturesและdetectDragGesturesAfterLongPress - การเปลี่ยนรูปแบบ:
detectTransformGestures
ตัวตรวจจับเหล่านี้เป็นตัวตรวจจับระดับบนสุด คุณจึงไม่สามารถเพิ่มตัวตรวจจับหลายรายการภายในตัวแก้ไข pointerInput รายการเดียวได้ ข้อมูลโค้ดต่อไปนี้จะตรวจจับเฉพาะการแตะ ไม่ใช่การลาก
var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(Unit) { detectTapGestures { log = "Tap!" } // Never reached detectDragGestures { _, _ -> log = "Dragging" } } ) }
ภายใน เมธอด detectTapGestures จะบล็อกโครูทีน และระบบจะไม่เข้าถึงตัวตรวจจับที่ 2 หากต้องการเพิ่ม Listener ท่าทางสัมผัสมากกว่า 1 รายการลงใน Composable ให้ใช้อินสแตนซ์ตัวแก้ไข pointerInput แยกกันแทน ดังนี้
var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(Unit) { detectTapGestures { log = "Tap!" } } .pointerInput(Unit) { // These drag events will correctly be triggered detectDragGestures { _, _ -> log = "Dragging" } } ) }
จัดการเหตุการณ์ต่อท่าทางสัมผัส
ตามคำจำกัดความ ท่าทางสัมผัสจะเริ่มต้นด้วยเหตุการณ์การกดตัวชี้ลง คุณสามารถใช้เมธอดตัวช่วย awaitEachGesture แทนลูป while(true) ที่ส่งผ่านเหตุการณ์ข้อมูลดิบแต่ละรายการได้ เมธอด awaitEachGesture จะรีสตาร์ทบล็อกที่มีอยู่เมื่อยกเคอร์เซอร์ทั้งหมดขึ้น ซึ่งบ่งชี้ว่าท่าทางสัมผัสเสร็จสมบูรณ์แล้ว
@Composable private fun SimpleClickable(onClick: () -> Unit) { Box( Modifier .size(100.dp) .pointerInput(onClick) { awaitEachGesture { awaitFirstDown().also { it.consume() } val up = waitForUpOrCancellation() if (up != null) { up.consume() onClick() } } } ) }
ในทางปฏิบัติ คุณมักจะต้องการใช้ awaitEachGesture เสมอ เว้นแต่คุณจะตอบสนองต่อเหตุการณ์เคอร์เซอร์โดยไม่ระบุท่าทางสัมผัส ตัวอย่างเช่น hoverable ซึ่งไม่ตอบสนองต่อเหตุการณ์การกดหรือปล่อยตัวชี้ แต่ต้องการทราบเพียงว่าตัวชี้เข้าหรือออกจากขอบเขตเมื่อใด
รอเหตุการณ์หรือท่าทางสัมผัสย่อยที่เฉพาะเจาะจง
มีชุดเมธอดที่ช่วยระบุส่วนที่เหมือนกันของท่าทางสัมผัส ดังนี้
- ระงับจนกว่าตัวชี้จะเลื่อนลงด้วย
awaitFirstDownหรือรอให้ตัวชี้ทั้งหมดเลื่อนขึ้นด้วยwaitForUpOrCancellation - สร้าง Listener การลากระดับต่ำโดยใช้
awaitTouchSlopOrCancellationและawaitDragOrCancellationตัวแฮนเดิลท่าทางสัมผัสจะระงับก่อนจนกว่าตัวชี้จะถึงระยะการแตะที่อนุญาต จากนั้นจะระงับจนกว่าเหตุการณ์การลากครั้งแรกจะเกิดขึ้น หากคุณสนใจเฉพาะการลากตามแกนเดียว ให้ใช้awaitHorizontalTouchSlopOrCancellationบวกawaitHorizontalDragOrCancellationหรือawaitVerticalTouchSlopOrCancellationบวกawaitVerticalDragOrCancellationแทน - ระงับจนกว่าจะมีการกดค้างด้วย
awaitLongPressOrCancellation - ใช้เมธอด
dragเพื่อฟังเหตุการณ์การลากอย่างต่อเนื่อง หรือhorizontalDragหรือverticalDragเพื่อฟังเหตุการณ์การลากในแกนเดียว
ใช้การคำนวณสำหรับเหตุการณ์แบบมัลติทัช
เมื่อผู้ใช้ใช้ท่าทางสัมผัสแบบมัลติทัชโดยใช้ตัวชี้มากกว่า 1 ตัว การทำความเข้าใจการเปลี่ยนรูปแบบที่จำเป็นตามค่าดิบนั้นเป็นเรื่องที่ซับซ้อน
หากตัวแก้ไข transformable หรือเมธอด detectTransformGestures ไม่ได้ให้การควบคุมที่ละเอียดเพียงพอสำหรับกรณีการใช้งานของคุณ คุณสามารถฟังเหตุการณ์ดิบและใช้การคำนวณกับเหตุการณ์เหล่านั้นได้ เมธอดตัวช่วยเหล่านี้ได้แก่ calculateCentroid, calculateCentroidSize, calculatePan, calculateRotation และ calculateZoom
การส่งเหตุการณ์และการทดสอบตัวชี้
ระบบจะไม่ส่งเหตุการณ์เคอร์เซอร์ทุกรายการไปยังตัวแก้ไข pointerInput ทุกตัว การส่งเหตุการณ์จะทำงานดังนี้
- ระบบจะส่งเหตุการณ์ตัวชี้ไปยังลำดับชั้นที่ประกอบกันได้ ทันทีที่ตัวชี้ใหม่ทริกเกอร์เหตุการณ์ตัวชี้แรก ระบบจะเริ่มการทดสอบตัวชี้กับ Composable ที่ "มีสิทธิ์" Composable จะถือว่ามีสิทธิ์เมื่อมีความสามารถในการจัดการอินพุตตัวชี้ การทดสอบตัวชี้จะเริ่มจากด้านบนของโครงสร้าง UI ไปยังด้านล่าง ระบบจะ "Hit" Composable เมื่อเหตุการณ์เคอร์เซอร์เกิดขึ้นภายในขอบเขตของ Composable นั้น กระบวนการนี้ส่งผลให้เกิดเชนของ Composable ที่ผ่านการทดสอบตัวชี้
- โดยค่าเริ่มต้น เมื่อมี Composable ที่มีสิทธิ์หลายรายการในระดับเดียวกันของต้นไม้ ระบบจะ "Hit" เฉพาะ Composable ที่มีดัชนีลำดับ Z สูงสุดเท่านั้น ตัวอย่างเช่น เมื่อคุณเพิ่ม
Buttoncomposable ที่ซ้อนทับกัน 2 รายการลงในBoxจะมีเพียงรายการที่วาดไว้ด้านบนเท่านั้นที่ได้รับเหตุการณ์ตัวชี้ ในทางทฤษฎี คุณสามารถลบล้างลักษณะการทำงานนี้ได้โดยสร้างการติดตั้งใช้งานPointerInputModifierNodeของคุณเองและตั้งค่าsharePointerInputWithSiblingsเป็น "จริง" - ระบบจะส่งเหตุการณ์เพิ่มเติมสำหรับตัวชี้เดียวกันไปยังเชนของ Composable เดียวกัน และจะไหลตามตรรกะการเผยแพร่เหตุการณ์ ระบบจะไม่ทำการทดสอบตัวชี้สำหรับตัวชี้นี้อีกต่อไป ซึ่งหมายความว่า Composable แต่ละรายการในเชนจะได้รับเหตุการณ์ทั้งหมดสำหรับตัวชี้ดังกล่าว แม้ว่าเหตุการณ์เหล่านั้นจะเกิดขึ้นนอกขอบเขตของ Composable นั้นก็ตาม คอมโพสิเบิลที่ไม่ได้อยู่ในเชนจะไม่ได้รับเหตุการณ์เคอร์เซอร์ แม้ว่าเคอร์เซอร์จะอยู่ภายในขอบเขตก็ตาม
เหตุการณ์การวางเมาส์เหนือองค์ประกอบ ซึ่งทริกเกอร์โดยการวางเมาส์หรือสไตลัสเหนือองค์ประกอบ เป็นข้อยกเว้นของกฎที่กำหนดไว้ที่นี่ ระบบจะส่งเหตุการณ์การวางเมาส์เหนือไปยัง Composable ที่เหตุการณ์นั้นโดน ดังนั้นเมื่อผู้ใช้วางเคอร์เซอร์เหนือขอบเขตของ Composable หนึ่งไปยังอีก Composable หนึ่ง ระบบจะส่งเหตุการณ์ไปยัง Composable ใหม่แทนที่จะส่งเหตุการณ์ไปยัง Composable แรก
การใช้งานตามเหตุการณ์
เมื่อ Composable มากกว่า 1 รายการมีเครื่องจัดการท่าทางสัมผัสที่กำหนดไว้ เครื่องจัดการเหล่านั้นไม่ควรขัดแย้งกัน ตัวอย่างเช่น ลองดู UI ต่อไปนี้
เมื่อผู้ใช้แตะปุ่มบุ๊กมาร์ก แลมบ์ดา onClick ของปุ่มจะจัดการท่าทางสัมผัสนั้น เมื่อผู้ใช้แตะส่วนอื่นๆ ของรายการในลิสต์ ListItem จะจัดการท่าทางสัมผัสนั้นและไปยังบทความ ในแง่ของอินพุตตัวชี้ ปุ่มต้องใช้เหตุการณ์นี้ เพื่อให้องค์ประกอบหลักทราบว่าไม่ต้องตอบสนองต่อเหตุการณ์นั้นอีก ท่าทางสัมผัสที่รวมอยู่ในคอมโพเนนต์ที่พร้อมใช้งานทันทีและตัวปรับแต่งท่าทางสัมผัสทั่วไปจะรวมลักษณะการใช้งานนี้ไว้ด้วย แต่หากคุณเขียนท่าทางสัมผัสที่กำหนดเอง คุณต้องใช้เหตุการณ์ด้วยตนเอง โดยใช้เมธอด PointerInputChange.consume ดังนี้
Modifier.pointerInput(Unit) { awaitEachGesture { while (true) { val event = awaitPointerEvent() // consume all changes event.changes.forEach { it.consume() } } } }
การใช้เหตุการณ์ไม่ได้หยุดการเผยแพร่เหตุการณ์ไปยัง Composable อื่นๆ แต่ Composable ต้องละเว้นเหตุการณ์ที่ใช้ไปแล้วอย่างชัดเจนแทน เมื่อเขียนท่าทางสัมผัสที่กำหนดเอง คุณควรตรวจสอบว่าองค์ประกอบอื่นใช้เหตุการณ์ไปแล้วหรือไม่ โดยทำดังนี้
Modifier.pointerInput(Unit) { awaitEachGesture { while (true) { val event = awaitPointerEvent() if (event.changes.any { it.isConsumed }) { // A pointer is consumed by another gesture handler } else { // Handle unconsumed event } } } }
การเผยแพร่เหตุการณ์
ดังที่ได้กล่าวไปก่อนหน้านี้ ระบบจะส่งการเปลี่ยนแปลงตัวชี้ไปยัง Composable แต่ละรายการที่ตัวชี้ไปโดน
แต่หากมี Composable ดังกล่าวมากกว่า 1 รายการ เหตุการณ์จะเผยแพร่ตามลำดับใด หากคุณดูตัวอย่างจากส่วนที่แล้ว UI นี้จะแปลเป็นแผนผัง UI ต่อไปนี้ ซึ่งมีเพียง ListItem และ Button เท่านั้นที่ตอบสนองต่อเหตุการณ์เคอร์เซอร์
เหตุการณ์เคอร์เซอร์จะไหลผ่าน Composable แต่ละรายการเหล่านี้ 3 ครั้งในระหว่าง "การส่งผ่าน" 3 ครั้ง ดังนี้
- ในการส่งผ่านครั้งแรก เหตุการณ์จะไหลจากด้านบนของแผนผัง UI ไปยังด้านล่าง โฟลว์นี้ช่วยให้ผู้ปกครองสกัดกั้นเหตุการณ์ก่อนที่บุตรหลานจะใช้เหตุการณ์นั้นได้ ตัวอย่างเช่น เคล็ดลับเครื่องมือต้องขัดจังหวะการกดค้างแทนที่จะส่งต่อไปยังองค์ประกอบย่อย ในตัวอย่างของเรา
ListItemจะได้รับเหตุการณ์ก่อนButton - ในรอบหลัก เหตุการณ์จะไหลจากโหนด Leaf ของแผนผัง UI ไปยังรูทของแผนผัง UI ระยะนี้เป็นระยะที่คุณใช้ท่าทางสัมผัสตามปกติ และเป็นระยะเริ่มต้นเมื่อฟังเหตุการณ์ การจัดการท่าทางสัมผัสในขั้นตอนนี้หมายความว่าโหนดปลายสุดจะมีลำดับความสำคัญเหนือโหนดหลัก ซึ่งเป็นลักษณะการทำงานที่สมเหตุสมผลที่สุดสำหรับท่าทางสัมผัสส่วนใหญ่ ในตัวอย่างของเรา
Buttonจะได้รับเหตุการณ์ก่อนListItem - ในรอบสุดท้าย เหตุการณ์จะไหลอีกครั้งจากด้านบนของแผนผัง UI ไปยังโหนดปลายสุด โฟลว์นี้ช่วยให้องค์ประกอบที่อยู่สูงกว่าในสแต็กตอบสนองต่อการใช้เหตุการณ์โดยองค์ประกอบหลักได้ ตัวอย่างเช่น ปุ่มจะนำการแสดงผลริปเปิลออกเมื่อการกดเปลี่ยนเป็นการลากองค์ประกอบหลักที่เลื่อนได้
ภาพแสดงขั้นตอนของเหตุการณ์มีลักษณะดังนี้
เมื่อใช้การเปลี่ยนแปลงอินพุตแล้ว ระบบจะส่งข้อมูลนี้จากจุดนั้นในขั้นตอนต่อไปนี้
ในโค้ด คุณสามารถระบุบัตรที่สนใจได้ดังนี้
Modifier.pointerInput(Unit) { awaitPointerEventScope { val eventOnInitialPass = awaitPointerEvent(PointerEventPass.Initial) val eventOnMainPass = awaitPointerEvent(PointerEventPass.Main) // default val eventOnFinalPass = awaitPointerEvent(PointerEventPass.Final) } }
ในข้อมูลโค้ดนี้ การเรียกใช้เมธอด await แต่ละรายการจะแสดงเหตุการณ์เดียวกัน แม้ว่าข้อมูลเกี่ยวกับการใช้จะมีการเปลี่ยนแปลงก็ตาม
ทดสอบท่าทางสัมผัส
ในเมธอดการทดสอบ คุณสามารถส่งเหตุการณ์ตัวชี้ด้วยตนเองได้โดยใช้เมธอด performTouchInput ซึ่งช่วยให้คุณใช้ท่าทางสัมผัสแบบเต็มระดับสูง (เช่น บีบหรือคลิกค้าง) หรือท่าทางสัมผัสระดับต่ำ (เช่น เลื่อนเคอร์เซอร์ตามจำนวนพิกเซลที่กำหนด) ได้ ดังนี้
composeTestRule.onNodeWithTag("MyList").performTouchInput { swipeUp() swipeDown() click() }
ดูตัวอย่างเพิ่มเติมในเอกสารประกอบของ performTouchInput
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับท่าทางสัมผัสใน Jetpack Compose ได้จากแหล่งข้อมูลต่อไปนี้
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การช่วยเหลือพิเศษใน Compose
- เลื่อน
- แตะและกด