เมื่อบริการการช่วยเหลือพิเศษไปยังส่วนต่างๆ ขององค์ประกอบบนหน้าจอ องค์ประกอบเหล่านี้ต้องจัดกลุ่ม แยก หรือแม้แต่ซ่อนไว้ในระดับความละเอียดที่เหมาะสม เมื่อคอมโพสิชันระดับล่างทุกรายการในหน้าจอไฮไลต์แยกกัน ผู้ใช้จะต้องโต้ตอบหลายครั้งเพื่อไปยังส่วนต่างๆ ของหน้าจอ หากผสานองค์ประกอบเข้าด้วยกันมากเกินไป ผู้ใช้อาจไม่เข้าใจว่าองค์ประกอบใดควรอยู่ด้วยกันตามหลักเหตุผล หากมีองค์ประกอบบนหน้าจอที่ตกแต่งเพื่อความสวยงามเท่านั้น บริการเพื่อการเข้าถึงอาจซ่อนองค์ประกอบเหล่านี้ไว้ ในกรณีเหล่านี้ คุณสามารถใช้ Compose API เพื่อผสาน ล้าง และซ่อนความหมายได้
ความหมายแบบผสาน
เมื่อคุณใช้ตัวแก้ไข clickable
กับคอมโพสิชันหลัก คอมโพสิชันจะผสานองค์ประกอบย่อยทั้งหมดที่อยู่ภายใต้คอมโพสิชันนั้นโดยอัตโนมัติ หากต้องการทำความเข้าใจวิธีที่คอมโพเนนต์ Compose Material และ Foundation แบบอินเทอร์แอกทีฟใช้กลยุทธ์การผสานโดยค่าเริ่มต้น โปรดดูที่ส่วนองค์ประกอบแบบอินเทอร์แอกทีฟ
คอมโพเนนต์หนึ่งๆ อาจมีคอมโพสิเบิลหลายรายการ คอมโพสิเบิลเหล่านี้อาจสร้างกลุ่มตามตรรกะและแต่ละรายการอาจมีข้อมูลสำคัญ แต่คุณอาจยังต้องการให้บริการการช่วยเหลือพิเศษแสดงคอมโพสิเบิลเหล่านี้เป็นองค์ประกอบเดียว
ตัวอย่างเช่น ลองนึกถึงคอมโพสิเบิลที่แสดงรูปโปรไฟล์ ชื่อ และข้อมูลเพิ่มเติมของผู้ใช้

คุณสามารถเปิดใช้การคอมไพล์เพื่อผสานองค์ประกอบเหล่านี้ได้โดยใช้พารามิเตอร์ 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
คอมโพสิเบิลคอมโพสิเบิลบางรายการจะไม่ผสานภายใต้รายการหลักโดยอัตโนมัติตามการออกแบบ องค์ประกอบหลักจะผสานองค์ประกอบย่อยไม่ได้เมื่อองค์ประกอบย่อยกำลังผสานอยู่ด้วย ไม่ว่าจะเป็นจากการตั้งค่า mergeDescendants = true
อย่างชัดแจ้ง หรือเป็นคอมโพเนนต์ที่ผสานตัวเอง เช่น ปุ่มหรือองค์ประกอบที่คลิกได้ การทราบว่า API บางรายการผสานหรือปฏิเสธการผสานอย่างไรจะช่วยให้คุณแก้ไขข้อบกพร่องของลักษณะการทำงานบางอย่างที่อาจไม่คาดคิดได้
ใช้การผสานเมื่อองค์ประกอบย่อยประกอบกันเป็นกลุ่มที่สมเหตุสมผลและตรรกะภายใต้องค์ประกอบหลัก แต่หากรายการย่อยที่ฝังอยู่ต้องมีการปรับหรือนําความหมายของรายการย่อยออกด้วยตนเอง API อื่นๆ อาจเหมาะกับความต้องการของคุณมากกว่า (เช่น clearAndSetSemantics
)
ล้างและตั้งค่าความหมาย
หากจำเป็นต้องล้างหรือเขียนทับข้อมูลเชิงความหมายทั้งหมด ให้ใช้ clearAndSetSemantics
ซึ่งเป็น API ที่มีประสิทธิภาพ
เมื่อคอมโพเนนต์ต้องการล้างความหมายของคอมโพเนนต์เองและความหมายของคอมโพเนนต์ที่สืบทอดมา ให้ใช้ 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 และบริการที่คล้ายกันอาจใช้ข้อมูลเชิงอรรถศาสตร์เพื่อทำความเข้าใจหน้าจอ ดังนั้นคุณจึงควรล้างข้อมูลดังกล่าวเมื่อจำเป็นเท่านั้น
- คุณอาจตั้งค่าความหมายที่กำหนดเองภายใน API Lambda ได้
- ลําดับของตัวแก้ไขมีความสำคัญ เนื่องจาก 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
ที่นี่จะทำให้ระบบซ่อนลายน้ำและการตกแต่งจากบริการการช่วยเหลือพิเศษ แต่ยังคงเก็บความหมายขององค์ประกอบไว้สำหรับกรณีการใช้งานอื่นๆ เช่น การทดสอบ
รายละเอียดกรณีการใช้งาน
ต่อไปนี้เป็นสรุป Use Case เพื่อทำความเข้าใจวิธีแยกความแตกต่างระหว่าง API เวอร์ชันเก่าอย่างชัดเจน
- กรณีที่เนื้อหาไม่ได้มีไว้เพื่อให้บริการการช่วยเหลือพิเศษนำไปใช้
- ใช้
hideFromAccessibility
เมื่อเนื้อหาอาจเป็นการตกแต่งหรือซ้ำซ้อน แต่ยังคงต้องทดสอบ - ใช้
clearAndSetSemantics{}
กับ Lambda ว่างเมื่อต้องล้างความหมายขององค์ประกอบหลักและองค์ประกอบย่อยสำหรับบริการทั้งหมด - ใช้
clearAndSetSemantics{/*content*/}
กับเนื้อหาภายใน Lambda เมื่อต้องตั้งค่าความหมายของคอมโพเนนต์ด้วยตนเอง
- ใช้
- กรณีที่ควรถือว่าเนื้อหาเป็นเอนทิตีเดียวและข้อมูลของเนื้อหาย่อยทั้งหมดต้องสมบูรณ์
- ใช้รายการที่สืบทอดตามความหมายแบบผสาน

แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การช่วยเหลือพิเศษในเครื่องมือเขียน
- [Material Design 2 ใน Compose][19]
- การทดสอบเลย์เอาต์การเขียน