เมื่อบริการการช่วยเหลือพิเศษไปยังส่วนต่างๆ ขององค์ประกอบบนหน้าจอ สิ่งสำคัญคือต้องจัดกลุ่ม แยก หรือแม้แต่ซ่อนองค์ประกอบเหล่านี้ในระดับความละเอียดที่เหมาะสม เมื่อมีการไฮไลต์ Composable ระดับต่ำทุกรายการในหน้าจอแยกกัน ผู้ใช้จะต้องโต้ตอบหลายครั้งเพื่อเลื่อนไปทั่วหน้าจอ หากองค์ประกอบรวมกันมากเกินไป ผู้ใช้อาจไม่เข้าใจว่าองค์ประกอบใดควรอยู่ด้วยกันตามหลักเหตุผล หากมีองค์ประกอบบนหน้าจอที่ใช้เพื่อตกแต่งเท่านั้น คุณสามารถซ่อนองค์ประกอบเหล่านี้จากบริการการช่วยเหลือพิเศษได้ ในกรณีเหล่านี้ คุณสามารถใช้ Compose API เพื่อผสาน ล้าง และซ่อนความหมายได้
รวมความหมาย
เมื่อคุณใช้ตัวแก้ไข clickable กับ Composable ระดับบนสุด Compose จะผสานองค์ประกอบย่อยทั้งหมดที่อยู่ภายใต้องค์ประกอบนั้นโดยอัตโนมัติ หากต้องการทำความเข้าใจวิธีที่คอมโพเนนต์ Compose Material และ Foundation แบบอินเทอร์แอกทีฟใช้กลยุทธ์การผสานโดยค่าเริ่มต้น โปรดดูส่วนองค์ประกอบแบบอินเทอร์แอกทีฟ
คอมโพเนนต์มักประกอบด้วย Composable หลายรายการ Composable เหล่านี้อาจสร้างกลุ่มเชิงตรรกะและแต่ละรายการอาจมีข้อมูลสำคัญ แต่คุณอาจยังต้องการให้บริการการช่วยเหลือพิเศษมองเห็นเป็นองค์ประกอบเดียว
ตัวอย่างเช่น ลองนึกถึง Composable ที่แสดงรูปโปรไฟล์ ชื่อ และข้อมูลเพิ่มเติมของผู้ใช้
คุณสามารถเปิดใช้ Compose เพื่อผสานองค์ประกอบเหล่านี้ได้โดยใช้พารามิเตอร์ mergeDescendants ในตัวแก้ไขความหมาย วิธีนี้จะทำให้บริการการช่วยเหลือพิเศษถือว่าคอมโพเนนต์เป็นเอนทิตีเดียว และพร็อพเพอร์ตี้เชิงความหมายทั้งหมดขององค์ประกอบสืบทอดจะผสานรวมกัน ดังนี้
@Composable private fun PostMetadata(metadata: Metadata) { // Merge elements below for accessibility purposes Row(modifier = Modifier.semantics(mergeDescendants = true) {}) { Image( imageVector = Icons.Filled.AccountCircle, contentDescription = null // decorative ) Column { Text(metadata.author.name) Text("${metadata.date} • ${metadata.readTimeMinutes} min read") } } }
ตอนนี้บริการการช่วยเหลือพิเศษจะมุ่งเน้นที่คอนเทนเนอร์ทั้งหมดพร้อมกัน และผสานรวมเนื้อหาของคอนเทนเนอร์ ดังนี้
พร็อพเพอร์ตี้ความหมายแต่ละรายการมีกลยุทธ์การผสานที่กำหนดไว้ เช่น พร็อพเพอร์ตี้ ContentDescription จะเพิ่มค่า ContentDescription ทั้งหมดที่สืบทอดมาลงในรายการ คุณตรวจสอบกลยุทธ์การผสานของพร็อพเพอร์ตี้ความหมายได้โดยตรวจสอบการใช้งาน mergePolicy ใน SemanticsProperties.kt
พร็อพเพอร์ตี้สามารถใช้ค่าหลักหรือค่ารอง รวมค่าเป็นรายการหรือสตริง ไม่อนุญาตให้รวมเลยและแสดงข้อยกเว้นแทน หรือกลยุทธ์การรวมที่กำหนดเองอื่นๆ
มีสถานการณ์อื่นๆ ที่คุณคาดหวังให้ระบบผสานความหมายขององค์ประกอบย่อยเข้ากับองค์ประกอบหลัก แต่กลับไม่เป็นเช่นนั้น ในตัวอย่างต่อไปนี้ เรามีองค์ประกอบหลักของรายการ clickable ที่มีองค์ประกอบย่อย และเราอาจคาดหวังว่าองค์ประกอบหลักจะผสานองค์ประกอบทั้งหมดเข้าด้วยกัน
@Composable private fun ArticleListItem( openArticle: () -> Unit, addToBookmarks: () -> Unit, ) { Row(modifier = Modifier.clickable { openArticle() }) { // Merges with parent clickable: Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Article thumbnail" ) ArticleDetails() // Defies the merge due to its own clickable: BookmarkButton(onClick = addToBookmarks) } }
เมื่อผู้ใช้กดรายการ clickable Row ระบบจะเปิดบทความ ด้านในมี BookmarkButton เพื่อบุ๊กมาร์กบทความ ปุ่มที่ฝังนี้จะแสดงเป็นแบบไม่ผสานรวม ในขณะที่เนื้อหาที่ฝังอื่นๆ ภายในแถวจะผสานรวมกัน
Row แผนผังที่ไม่ได้ผสานจะมีโหนดแยกต่างหากสำหรับ Text composableคอมโพสิเบิลบางรายการไม่ได้ผสานรวมโดยอัตโนมัติภายใต้คอมโพสิเบิลหลักตามการออกแบบ องค์ประกอบหลักไม่สามารถผสานองค์ประกอบย่อยเมื่อองค์ประกอบย่อยกำลังผสานด้วย ไม่ว่าจะจากการตั้งค่า mergeDescendants = true อย่างชัดแจ้งหรือจากการเป็นคอมโพเนนต์ที่ผสานตัวเอง เช่น ปุ่มหรือองค์ประกอบที่คลิกได้ การทราบวิธีที่ API บางรายการผสานหรือปฏิเสธการผสานจะช่วยคุณแก้ไขข้อบกพร่องของลักษณะการทำงานที่อาจไม่คาดคิดได้
ใช้การผสานเมื่อองค์ประกอบย่อยประกอบกันเป็นกลุ่มที่สมเหตุสมผลและเหมาะสมภายใต้องค์ประกอบหลัก แต่หากองค์ประกอบย่อยที่ฝังอยู่จำเป็นต้องมีการปรับหรือนำความหมายของตนเองออกด้วยตนเอง API อื่นๆ อาจเหมาะกับความต้องการของคุณมากกว่า (เช่น clearAndSetSemantics)
ล้างและตั้งค่าความหมาย
หากจำเป็นต้องล้างหรือเขียนทับข้อมูลเชิงความหมายทั้งหมด API ที่มีประสิทธิภาพที่ควรใช้คือ clearAndSetSemantics
เมื่อคอมโพเนนต์ต้องการล้างความหมายของตัวเองและองค์ประกอบสืบทอด ให้ใช้ API นี้กับ Lambda ที่ว่างเปล่า เมื่อต้องเขียนทับความหมาย ให้ใส่เนื้อหาใหม่ไว้ใน Lambda
โปรดทราบว่าเมื่อล้างด้วย Lambda ที่ว่างเปล่า ระบบจะไม่ส่งความหมายที่ล้างแล้วไปยังผู้บริโภคที่ใช้ข้อมูลนี้ เช่น การช่วยเหลือพิเศษ การป้อนข้อความอัตโนมัติ หรือการทดสอบ เมื่อเขียนทับเนื้อหาด้วย clearAndSetSemantics{/*semantic information*/} ความหมายใหม่จะแทนที่ความหมายก่อนหน้าทั้งหมดขององค์ประกอบและองค์ประกอบสืบทอด
ต่อไปนี้เป็นตัวอย่างคอมโพเนนต์ปุ่มเปิด/ปิดที่กำหนดเอง ซึ่งแสดงด้วยแถวที่โต้ตอบได้ซึ่งมีไอคอนและข้อความ
// Developer might intend this to be a toggleable. // Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied, // a custom description is set, and a Role is applied. @Composable fun FavoriteToggle() { val checked = remember { mutableStateOf(true) } Row( modifier = Modifier .toggleable( value = checked.value, onValueChange = { checked.value = it } ) .clearAndSetSemantics { stateDescription = if (checked.value) "Favorited" else "Not favorited" toggleableState = ToggleableState(checked.value) role = Role.Switch }, ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null // not needed here ) Text("Favorite?") } }
แม้ว่าไอคอนและข้อความจะมีข้อมูลเชิงความหมายอยู่บ้าง แต่เมื่อรวมกันแล้วก็ไม่ได้บ่งบอกว่าคอมโพเนนต์นี้เปิด/ปิดได้ การผสานไม่เพียงพอเนื่องจากคุณต้องให้ข้อมูลเพิ่มเติมเกี่ยวกับองค์ประกอบ
เนื่องจากข้อมูลโค้ดด้านบนสร้างคอมโพเนนต์การสลับที่กำหนดเอง คุณจึงต้องเพิ่มความสามารถในการสลับ รวมถึงความหมายของ stateDescription, toggleableState และ role วิธีนี้จะทำให้สถานะคอมโพเนนต์และการดำเนินการที่เกี่ยวข้องพร้อมใช้งาน เช่น TalkBack จะประกาศว่า "แตะสองครั้งเพื่อสลับ" แทนที่จะเป็น "แตะสองครั้งเพื่อเปิดใช้งาน"
การล้างความหมายเดิมและตั้งค่าความหมายใหม่ที่สื่อความหมายมากขึ้นช่วยให้บริการการช่วยเหลือพิเศษเห็นว่านี่เป็นคอมโพเนนต์ที่สลับได้ซึ่งสามารถสลับสถานะได้
เมื่อใช้ clearAndSetSemantics โปรดคำนึงถึงสิ่งต่อไปนี้
- เนื่องจากบริการจะไม่ได้รับข้อมูลเมื่อตั้งค่า API นี้ จึงควรใช้ API นี้เท่าที่จำเป็น
- AI Agent และบริการที่คล้ายกันอาจใช้ข้อมูลความหมายเพื่อทำความเข้าใจหน้าจอ ดังนั้นจึงควรล้างข้อมูลเมื่อจำเป็นเท่านั้น
- คุณอาจตั้งค่าความหมายที่กำหนดเองภายใน Lambda ของ API ได้
- ลำดับของตัวแก้ไขมีความสำคัญ โดย API นี้จะล้างความหมายทั้งหมดที่อยู่หลังตำแหน่งที่ใช้ โดยไม่คำนึงถึงกลยุทธ์การผสานอื่นๆ
ซ่อนความหมาย
ในบางสถานการณ์ ไม่จำเป็นต้องส่งองค์ประกอบไปยังบริการการช่วยเหลือพิเศษ เนื่องจากข้อมูลเพิ่มเติมอาจซ้ำซ้อนสำหรับการช่วยเหลือพิเศษ หรือเป็นเพียงการตกแต่งภาพและไม่มีการโต้ตอบ ในกรณีเหล่านี้ คุณสามารถซ่อนองค์ประกอบด้วย hideFromAccessibility API
ตัวอย่างต่อไปนี้คือคอมโพเนนต์ที่อาจต้องซ่อน ได้แก่ ลายน้ำซ้ำซ้อนที่ครอบคลุมคอมโพเนนต์ และอักขระที่ใช้เพื่อแยกข้อมูลเพื่อการตกแต่ง
@Composable fun WatermarkExample( watermarkText: String, content: @Composable () -> Unit, ) { Box { WatermarkedContent() // Mark the watermark as hidden to accessibility services. WatermarkText( text = watermarkText, color = Color.Gray.copy(alpha = 0.5f), modifier = Modifier .align(Alignment.BottomEnd) .semantics { hideFromAccessibility() } ) } } @Composable fun DecorativeExample() { Text( modifier = Modifier.semantics { hideFromAccessibility() }, text = "A dot character that is used to decoratively separate information, like •" ) }
การใช้ hideFromAccessibility ที่นี่ช่วยให้มั่นใจได้ว่าลายน้ำและการตกแต่งจะถูกซ่อนจากบริการการช่วยเหลือพิเศษ แต่ยังคงรักษาความหมายไว้สำหรับกรณีการใช้งานอื่นๆ เช่น การทดสอบ
รายละเอียดกรณีการใช้งาน
ต่อไปนี้เป็นสรุปกรณีการใช้งานเพื่อทำความเข้าใจวิธีแยกความแตกต่างระหว่าง API ก่อนหน้าอย่างชัดเจน
- เมื่อเนื้อหาไม่ได้มีไว้เพื่อใช้โดยบริการการช่วยเหลือพิเศษ ให้ทำดังนี้
- ใช้
hideFromAccessibilityเมื่อเนื้อหาอาจเป็นเพียงการตกแต่งหรือซ้ำซ้อน แต่ยังคงต้องได้รับการทดสอบ - ใช้
clearAndSetSemantics{}กับ Lambda ที่ว่างเปล่าเมื่อต้องล้างความหมายของระดับบนและระดับล่างสำหรับบริการทั้งหมด - ใช้
clearAndSetSemantics{/*content*/}กับเนื้อหาภายใน Lambda เมื่อต้องตั้งค่าความหมายของคอมโพเนนต์ด้วยตนเอง
- ใช้
- เมื่อควรจัดการเนื้อหาเป็นเอนทิตีเดียว และต้องการข้อมูลย่อยทั้งหมดเพื่อให้สมบูรณ์ ให้ทำดังนี้
- ใช้การผสานองค์ประกอบย่อยที่สื่อความหมาย
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การช่วยเหลือพิเศษใน Compose
- [Material Design 2 ใน Compose][19]
- การทดสอบเลย์เอาต์ Compose