อรรถศาสตร์

นอกเหนือจากข้อมูลหลักที่ Composable มี เช่น สตริงข้อความของ Composable Text การมีข้อมูลเสริมเพิ่มเติมเกี่ยวกับองค์ประกอบ UI อาจเป็นประโยชน์

ข้อมูลเกี่ยวกับความหมายและบทบาทของคอมโพเนนต์ใน Compose เรียกว่าความหมาย ซึ่งเป็นวิธีให้บริบทเพิ่มเติมเกี่ยวกับ Composable แก่บริการต่างๆ เช่น การช่วยเหลือพิเศษ การป้อนข้อความอัตโนมัติ และการทดสอบ เช่น ไอคอนกล้องอาจเป็นเพียงรูปภาพในเชิงภาพ แต่ความหมายเชิงความหมายอาจเป็น "ถ่ายรูป"

การรวมความหมายที่เหมาะสมเข้ากับ Compose API ที่เหมาะสมจะช่วยให้คุณให้ข้อมูลเกี่ยวกับคอมโพเนนต์แก่บริการการช่วยเหลือพิเศษได้มากที่สุด ซึ่งจะตัดสินใจว่าจะแสดงคอมโพเนนต์ต่อผู้ใช้อย่างไร

Material และ Compose UI และ Foundation API มาพร้อมกับความหมายในตัวที่สอดคล้องกับบทบาทและฟังก์ชันเฉพาะของตน แต่คุณยังสามารถแก้ไขความหมายเหล่านี้สำหรับ API ที่มีอยู่หรือตั้งค่าความหมายใหม่สำหรับคอมโพเนนต์ที่กำหนดเองได้ตามข้อกำหนดเฉพาะของคุณ

พร็อพเพอร์ตี้เชิงความหมาย

พร็อพเพอร์ตี้เชิงความหมายจะสื่อความหมายของ Composable ที่เกี่ยวข้อง ตัวอย่างเช่น Composable Text มีพร็อพเพอร์ตี้เชิงความหมาย text เนื่องจากเป็นความหมายของ Composable นั้น Icon มีพร็อพเพอร์ตี้ contentDescription (หากนักพัฒนาแอปตั้งค่าไว้) ซึ่งสื่อความหมายของไอคอนเป็นข้อความ

พิจารณาว่าพร็อพเพอร์ตี้ความหมายสื่อความหมายของ Composable อย่างไร ลองพิจารณาSwitch โดยผู้ใช้จะเห็นดังนี้

รูปที่ 1 Switchในสถานะ "เปิด" และ "ปิด"

หากต้องการอธิบายความหมายขององค์ประกอบนี้ คุณอาจพูดว่า "นี่คือสวิตช์ ซึ่งเป็นองค์ประกอบที่สลับได้ในสถานะ 'เปิด' คุณสามารถคลิกเพื่อโต้ตอบได้"

ซึ่งเป็นสิ่งที่พร็อพเพอร์ตี้ความหมายใช้ทำโดยเฉพาะ โหนดความหมายขององค์ประกอบ Switch นี้มีพร็อพเพอร์ตี้ต่อไปนี้ตามที่แสดงด้วยเครื่องมือตรวจสอบเลย์เอาต์

เครื่องมือตรวจสอบเลย์เอาต์ที่แสดงพร็อพเพอร์ตี้ความหมายของ Composable ของ Switch
รูปที่ 2 เครื่องมือตรวจสอบเลย์เอาต์ที่แสดงพร็อพเพอร์ตี้ความหมายของ Switch composable

Role ระบุประเภทขององค์ประกอบ StateDescription อธิบายวิธีอ้างอิงสถานะ "เปิด" โดยค่าเริ่มต้น คำนี้จะเป็นคำว่า "เปิด" ในภาษาที่แปล แต่สามารถทำให้เจาะจงมากขึ้นได้ (เช่น "เปิดใช้") โดยอิงตามบริบท ToggleableState คือสถานะปัจจุบันของสวิตช์ พร็อพเพอร์ตี้ OnClick อ้างอิงถึงเมธอดที่ใช้ในการโต้ตอบกับองค์ประกอบนี้

การติดตามพร็อพเพอร์ตี้ความหมายของ Composable แต่ละรายการในแอปจะช่วยปลดล็อกความเป็นไปได้ที่มีประสิทธิภาพมากมาย ดังนี้

  • บริการการช่วยเหลือพิเศษใช้พร็อพเพอร์ตี้เพื่อแสดง UI ที่ปรากฏบนหน้าจอและอนุญาตให้ผู้ใช้โต้ตอบกับ UI ดังกล่าว สำหรับ Composable ของสวิตช์ TalkBack อาจประกาศว่า "เปิด สวิตช์ แตะสองครั้งเพื่อสลับ" ผู้ใช้สามารถแตะสองครั้งที่หน้าจอเพื่อปิดสวิตช์ได้
  • เฟรมเวิร์กการทดสอบใช้พร็อพเพอร์ตี้เพื่อค้นหาโหนด โต้ตอบกับโหนด และทำการยืนยัน ดังนี้
    val mySwitch = SemanticsMatcher.expectValue(
        SemanticsProperties.Role, Role.Switch
    )
    composeTestRule.onNode(mySwitch)
        .performClick()
        .assertIsOff()

คอมโพสิเบิลและตัวแก้ไขที่สร้างขึ้นบนไลบรารีพื้นฐานของ Compose จะตั้งค่าพร็อพเพอร์ตี้ที่เกี่ยวข้องให้คุณโดยค่าเริ่มต้นอยู่แล้ว คุณสามารถเปลี่ยนพร็อพเพอร์ตี้เหล่านี้ด้วยตนเองเพื่อปรับปรุงการรองรับการช่วยเหลือพิเศษสำหรับ Use Case ที่เฉพาะเจาะจง หรือเปลี่ยนกลยุทธ์การรวมหรือการล้างของ Composable ได้ (ไม่บังคับ)

หากต้องการส่งสัญญาณประเภทเนื้อหาที่เฉพาะเจาะจงของคอมโพเนนต์ไปยังบริการการช่วยเหลือพิเศษ คุณสามารถใช้ความหมายที่แตกต่างกันได้หลากหลาย ข้อมูลเพิ่มเติมเหล่านี้จะรองรับข้อมูลเชิงความหมายหลักที่มีอยู่ และช่วยให้บริการการช่วยเหลือพิเศษปรับแต่งวิธีแสดง ประกาศ หรือโต้ตอบกับคอมโพเนนต์ของคุณ

ดูรายการพร็อพเพอร์ตี้ความหมายทั้งหมดได้ที่ออบเจ็กต์ SemanticsProperties ดูรายการการดำเนินการเกี่ยวกับการช่วยเหลือพิเศษที่เป็นไปได้ทั้งหมดได้ที่ออบเจ็กต์ SemanticsActions

ส่วนหัว

แอปมักมีหน้าจอที่มีเนื้อหาแบบข้อความจำนวนมาก เช่น บทความยาวๆ หรือหน้าข่าว ซึ่งมักจะแบ่งออกเป็นส่วนย่อยๆ ที่มีส่วนหัว ดังนี้

บล็อกโพสต์ที่มีข้อความบทความในคอนเทนเนอร์ที่เลื่อนได้
รูปที่ 3 บล็อกโพสต์ที่มีข้อความบทความในคอนเทนเนอร์ที่เลื่อนได้

ผู้ใช้ที่มีความต้องการด้านการช่วยเหลือพิเศษอาจพบปัญหาในการไปยังส่วนต่างๆ ของหน้าจอดังกล่าวได้โดยง่าย บริการการช่วยเหลือพิเศษบางอย่างช่วยให้ไปยังส่วนต่างๆ หรือส่วนหัวได้โดยตรง เพื่อปรับปรุงประสบการณ์การไปยังส่วนต่างๆ หากต้องการเปิดใช้ฟีเจอร์นี้ ให้ระบุว่าคอมโพเนนต์ของคุณเป็น heading โดยกำหนดพร็อพเพอร์ตี้ Semantics ดังนี้

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

การแจ้งเตือนและป๊อปอัป

หากคอมโพเนนต์เป็นข้อความแจ้งเตือนหรือป๊อปอัป เช่น Snackbar คุณอาจต้องการส่งสัญญาณไปยังบริการการช่วยเหลือพิเศษว่าสามารถส่งโครงสร้างใหม่หรือการอัปเดตเนื้อหาไปยังผู้ใช้ได้

คอมโพเนนต์ที่คล้ายกับการแจ้งเตือนสามารถทำเครื่องหมายด้วยพร็อพเพอร์ตี้ความหมาย liveRegion ได้ ซึ่งจะช่วยให้บริการการช่วยเหลือพิเศษแจ้งเตือนผู้ใช้โดยอัตโนมัติเมื่อมีการเปลี่ยนแปลงในคอมโพเนนต์นี้หรือคอมโพเนนต์ย่อย

PopupAlert(
    message = "You have a new message",
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Polite
    }
)

คุณควรใช้ liveRegionMode.Polite ในกรณีส่วนใหญ่ที่ควรดึงดูดความสนใจของผู้ใช้ไปยังการแจ้งเตือนหรือเนื้อหาที่เปลี่ยนแปลงที่สำคัญบนหน้าจอเพียงสั้นๆ

คุณควรใช้ liveRegion.Assertive เท่าที่จำเป็นเพื่อหลีกเลี่ยงการรบกวนจากเสียงสะท้อน ควรใช้ในสถานการณ์ที่จำเป็นต้องแจ้งให้ผู้ใช้ทราบถึงเนื้อหาที่ต้องดำเนินการภายในเวลาที่กำหนด ดังนี้

PopupAlert(
    message = "Emergency alert incoming",
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Assertive
    }
)

ไม่ควรใช้ขอบเขตแบบสดกับเนื้อหาที่อัปเดตบ่อย เช่น นาฬิกานับเวลาถอยหลัง เพื่อหลีกเลี่ยงไม่ให้ผู้ใช้ได้รับความคิดเห็นอย่างต่อเนื่องมากเกินไป

คอมโพเนนต์ที่คล้ายหน้าต่าง

คอมโพเนนต์ที่กำหนดเองซึ่งมีลักษณะคล้ายหน้าต่าง เช่น ModalBottomSheet ต้องมีสัญญาณเพิ่มเติมเพื่อแยกความแตกต่างจากเนื้อหาโดยรอบ ในกรณีนี้ คุณสามารถใช้ความหมายของ paneTitle เพื่อให้การเปลี่ยนแปลงหน้าต่างหรือแผงที่เกี่ยวข้องแสดงอย่างเหมาะสมโดยบริการการช่วยเหลือพิเศษ พร้อมกับข้อมูลความหมายหลัก ดังนี้

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

โปรดดูข้อมูลอ้างอิงเกี่ยวกับวิธีที่ Material 3 ใช้ paneTitle สำหรับคอมโพเนนต์

คอมโพเนนต์ข้อผิดพลาด

สำหรับเนื้อหาประเภทอื่นๆ เช่น คอมโพเนนต์ที่คล้ายข้อผิดพลาด คุณอาจต้องการขยายข้อมูลความหมายหลักสำหรับผู้ใช้ที่มีความต้องการด้านการช่วยเหลือพิเศษ เมื่อกำหนดสถานะข้อผิดพลาด คุณสามารถแจ้งบริการการช่วยเหลือพิเศษเกี่ยวกับความหมาย error และแสดงข้อความแสดงข้อผิดพลาดแบบขยายได้

ในตัวอย่างนี้ TalkBack จะอ่านข้อมูลข้อความแสดงข้อผิดพลาดหลัก ตามด้วยข้อความเพิ่มเติมที่ขยายความ

Error(
    errorText = "Fields cannot be empty",
    modifier = Modifier
        .semantics {
            error("Please add both email and password")
        }
)

คอมโพเนนต์การติดตามความคืบหน้า

สำหรับคอมโพเนนต์ที่กำหนดเองซึ่งติดตามความคืบหน้า คุณอาจต้องการแจ้งให้ผู้ใช้ทราบถึงการเปลี่ยนแปลงความคืบหน้า ซึ่งรวมถึงค่าความคืบหน้าปัจจุบัน ช่วง และขนาดขั้น คุณสามารถทำได้ด้วยความหมายของ progressBarRangeInfo ซึ่งจะช่วยให้มั่นใจว่าบริการการช่วยเหลือพิเศษจะรับรู้ถึงการเปลี่ยนแปลงความคืบหน้า และสามารถอัปเดตผู้ใช้ตามนั้นได้ เทคโนโลยีความช่วยเหลือพิเศษที่แตกต่างกันอาจมีวิธีเฉพาะในการบอกใบ้ถึงความคืบหน้าที่เพิ่มขึ้นและลดลง

ProgressInfoBar(
    modifier = Modifier
        .semantics {
            progressBarRangeInfo =
                ProgressBarRangeInfo(
                    current = progress,
                    range = 0F..1F
                )
        }
)

ข้อมูลรายการและสินค้า

ในรายการและตารางกริดที่กำหนดเองซึ่งมีหลายรายการ บริการการช่วยเหลือพิเศษอาจได้รับประโยชน์จากการรับข้อมูลที่ละเอียดมากขึ้น เช่น จำนวนรายการและดัชนีทั้งหมด

การใช้ความหมายของ collectionInfo และ collectionItemInfo ในรายการและรายการตามลำดับในรายการที่ยาวนี้ บริการการช่วยเหลือพิเศษจะแจ้งให้ผู้ใช้ทราบถึงดัชนีรายการที่ผู้ใช้อยู่จากคอลเล็กชันทั้งหมด นอกเหนือจากข้อมูลความหมายที่เป็นข้อความ ดังนี้

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

คำอธิบายสถานะ

Composable สามารถกำหนด stateDescription สำหรับความหมายที่เฟรมเวิร์ก Android ใช้เพื่ออ่านสถานะที่ Composable อยู่ ตัวอย่างเช่น Composable ที่สลับได้อาจอยู่ในสถานะ "เลือก" หรือ "ไม่ได้เลือก" ในบางกรณี คุณอาจต้องการลบล้างป้ายกำกับคำอธิบายสถานะเริ่มต้นที่ Compose ใช้ ซึ่งทำได้โดยระบุป้ายกำกับคำอธิบายสถานะอย่างชัดเจนก่อนกำหนด Composable เป็นแบบเปิด/ปิดได้ ดังนี้

@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {
    val stateSubscribed = stringResource(R.string.subscribed)
    val stateNotSubscribed = stringResource(R.string.not_subscribed)
    Row(
        modifier = Modifier
            .semantics {
                // Set any explicit semantic properties
                stateDescription = if (selected) stateSubscribed else stateNotSubscribed
            }
            .toggleable(
                value = selected,
                onValueChange = { onToggle() }
            )
    ) {
        /* ... */
    }
}

การทำงานที่กำหนดเอง

การดำเนินการที่กำหนดเองสามารถใช้กับท่าทางสัมผัสบนหน้าจอสัมผัสที่ซับซ้อนมากขึ้น เช่น ปัดเพื่อปิดหรือลากและวาง เนื่องจากผู้ใช้ที่มีความบกพร่องทางการเคลื่อนไหวหรือความพิการอื่นๆ อาจโต้ตอบได้ยาก

หากต้องการให้ท่าทางสัมผัสปัดเพื่อปิดเข้าถึงได้ง่ายขึ้น คุณสามารถลิงก์กับการกระทำที่กำหนดเอง โดยส่งการดำเนินการปิดและป้ายกำกับที่นั่น

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

จากนั้นบริการการช่วยเหลือพิเศษ เช่น TalkBack จะไฮไลต์คอมโพเนนต์และบอกใบ้ว่ามีการดำเนินการเพิ่มเติมในเมนู ซึ่งแสดงถึงการปัดเพื่อปิดการดำเนินการ ดังนี้

การแสดงภาพเมนูการทำงานของ TalkBack
รูปที่ 4 ภาพเมนูการทำงานของ TalkBack

กรณีการใช้งานอีกกรณีหนึ่งสำหรับการกระทำที่กำหนดเองคือรายการยาวๆ ที่มีรายการซึ่งมีการกระทำที่ใช้ได้มากกว่า เนื่องจากผู้ใช้อาจรู้สึกเบื่อหน่ายกับการทำซ้ำการกระทำแต่ละอย่างสำหรับทุกรายการทีละรายการ

=การแสดงภาพการนำทางของการเข้าถึงด้วยสวิตช์บนหน้าจอ
รูปที่ 5 ภาพการไปยังส่วนต่างๆ ของการเข้าถึงด้วยสวิตช์บนหน้าจอ

หากต้องการปรับปรุงประสบการณ์การนำทาง ซึ่งมีประโยชน์อย่างยิ่งสำหรับเทคโนโลยีความช่วยเหลือพิเศษที่อิงตามการโต้ตอบ เช่น การเข้าถึงด้วยสวิตช์หรือการเข้าถึงด้วยเสียง คุณสามารถใช้การกระทำที่กำหนดเองในคอนเทนเนอร์เพื่อย้ายการกระทำออกจากการข้ามผ่านแต่ละรายการไปยังเมนูการทำงานแยกต่างหากได้ ดังนี้

ArticleListItemRow(
    modifier = Modifier
        .semantics {
            customActions = listOf(
                CustomAccessibilityAction(
                    label = "Open article",
                    action = {
                        openArticle()
                        true
                    }
                ),
                CustomAccessibilityAction(
                    label = "Add to bookmarks",
                    action = {
                        addToBookmarks()
                        true
                    }
                ),
            )
        }
) {
    Article(
        modifier = Modifier.clearAndSetSemantics { },
        onClick = openArticle,
    )
    BookmarkButton(
        modifier = Modifier.clearAndSetSemantics { },
        onClick = addToBookmarks,
    )
}

ในกรณีเหล่านี้ โปรดตรวจสอบว่าได้ล้างความหมายขององค์ประกอบย่อยเดิมด้วยตนเองโดยใช้ตัวปรับแต่ง clearAndSetSemantics เนื่องจากคุณกำลังย้ายองค์ประกอบย่อยเหล่านั้นไปยังการกระทำที่กำหนดเอง

ตัวอย่างเช่น เมื่อใช้การเข้าถึงด้วยสวิตช์ เมนูจะเปิดขึ้นเมื่อเลือกคอนเทนเนอร์และแสดงรายการการดำเนินการที่ฝังอยู่ซึ่งพร้อมใช้งาน ดังนี้

ไฮไลต์การเข้าถึงด้วยสวิตช์ของรายการบทความ
รูปที่ 6 ไฮไลต์การเข้าถึงด้วยสวิตช์ของรายการบทความ
การแสดงภาพเมนูการทำงานของการเข้าถึงด้วยสวิตช์
รูปที่ 7 ภาพเมนูการทำงานของการเข้าถึงด้วยสวิตช์

แผนผังความหมาย

Composition อธิบาย UI ของแอปและสร้างขึ้นโดยการเรียกใช้ Composable Composition คือโครงสร้างแบบต้นไม้ที่ประกอบด้วย Composable ซึ่งอธิบาย UI ของคุณ

ถัดจาก Composition จะมีต้นไม้แบบขนานที่เรียกว่าต้นไม้เชิงความหมาย แผนผังนี้อธิบาย UI ในลักษณะอื่นที่บริการการช่วยเหลือพิเศษและเฟรมเวิร์กการทดสอบเข้าใจได้ บริการการช่วยเหลือพิเศษใช้โครงสร้างนี้เพื่ออธิบายแอปให้ผู้ใช้ที่มีความต้องการเฉพาะฟัง เฟรมเวิร์กการทดสอบใช้โครงสร้างเพื่อโต้ตอบกับแอปและทำการยืนยันเกี่ยวกับแอป แผนผัง Semantics ไม่มีข้อมูลเกี่ยวกับวิธีวาด Composable แต่มีข้อมูลเกี่ยวกับความหมายเชิงความหมายของ Composable

ลำดับชั้น UI ทั่วไปและแผนผังความหมาย
รูปที่ 8 ลำดับชั้น UI ทั่วไปและแผนผังความหมาย

หากแอปประกอบด้วย Composable และตัวแก้ไขจากไลบรารี Compose Foundation และ Material ระบบจะสร้างและป้อนข้อมูลในแผนผังความหมายให้คุณโดยอัตโนมัติ อย่างไรก็ตาม เมื่อคุณเพิ่ม Composable ระดับต่ำที่กำหนดเอง คุณจะต้องระบุความหมายด้วยตนเอง นอกจากนี้ อาจมีบางสถานการณ์ที่ต้นไม้ไม่แสดงความหมายขององค์ประกอบบนหน้าจออย่างถูกต้องหรือครบถ้วน ซึ่งในกรณีนี้คุณสามารถปรับต้นไม้ได้

ลองดูตัวอย่าง Composable ของปฏิทินที่กำหนดเองนี้

Composable ปฏิทินที่กำหนดเองซึ่งมีองค์ประกอบวันที่ที่เลือกได้
รูปที่ 9 Composable ปฏิทินที่กำหนดเองซึ่งมีองค์ประกอบวันที่ที่เลือกได้

ในตัวอย่างนี้ ปฏิทินทั้งหมดจะใช้เป็น Composable ระดับต่ำรายการเดียว โดยใช้ Composable ของ Layout และวาดลงใน Canvas โดยตรง หากคุณไม่ดำเนินการใดๆ เพิ่มเติม บริการการช่วยเหลือพิเศษจะไม่ได้รับข้อมูลที่เพียงพอเกี่ยวกับเนื้อหาของ Composable และการเลือกของผู้ใช้ภายในปฏิทิน ตัวอย่างเช่น หากผู้ใช้คลิกวันที่ 17 เฟรมเวิร์กการช่วยเหลือพิเศษจะได้รับเฉพาะข้อมูลคำอธิบายสำหรับการควบคุมปฏิทินทั้งหมด ในกรณีนี้ บริการช่วยเหลือพิเศษ TalkBack จะประกาศว่า "ปฏิทิน" หรือ "ปฏิทินเดือนเมษายน" ซึ่งดีกว่าเพียงเล็กน้อย และผู้ใช้จะต้องสงสัยว่าเลือกวันใดไว้ หากต้องการทำให้ Composable นี้เข้าถึงได้มากขึ้น คุณจะต้องเพิ่มข้อมูลเชิงความหมายด้วยตนเอง

แผนผังที่ผสานและไม่ได้ผสาน

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

ตัวอย่างของ Composable ดังกล่าวคือ Button คุณสามารถให้เหตุผลเกี่ยวกับปุ่มเป็นองค์ประกอบเดียว แม้ว่าปุ่มนั้นอาจมีโหนดบุตรหลานหลายโหนดก็ตาม

Button(onClick = { /*TODO*/ }) {
    Icon(
        imageVector = Icons.Filled.Favorite,
        contentDescription = null
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
}

ในแผนผังความหมาย ระบบจะรวมพร็อพเพอร์ตี้ขององค์ประกอบสืบทอดของปุ่ม และปุ่มจะแสดงเป็นโหนดปลายสุดโหนดเดียวในแผนผัง ดังนี้

การแสดงความหมายของใบเดี่ยวที่ผสานรวม
รูปที่ 10 การแสดงความหมายของใบเดียวที่ผสานรวม

Composable และตัวแก้ไขสามารถระบุว่าต้องการผสานพร็อพเพอร์ตี้ความหมายขององค์ประกอบสืบทอดโดยเรียกใช้ Modifier.semantics (mergeDescendants = true) {} การตั้งค่าพร็อพเพอร์ตี้นี้เป็น true บ่งบอกว่าควรผสานพร็อพเพอร์ตี้ความหมาย ในตัวอย่าง Button คอมโพสิเบิล Button จะใช้ตัวแก้ไข clickable ภายในซึ่งรวมตัวแก้ไข semantics นี้ไว้ด้วย ดังนั้น ระบบจึงผสานโหนดสืบทอดของปุ่ม อ่านเอกสารประกอบเกี่ยวกับการช่วยเหลือพิเศษเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับกรณีที่คุณควรเปลี่ยนลักษณะการผสานรวมใน Composable

ตัวแก้ไขและ Composable หลายรายการในไลบรารี Foundation และ Material Compose มีการตั้งค่าพร็อพเพอร์ตี้นี้ เช่น ตัวแก้ไข clickable และ toggleable จะผสานองค์ประกอบสืบทอดโดยอัตโนมัติ นอกจากนี้ Composable ListItem จะผสานองค์ประกอบสืบทอดด้วย

ตรวจสอบแผนผัง

จริงๆ แล้วแผนผังความหมายเป็นแผนผัง 2 แบบที่แตกต่างกัน มีแผนผังความหมายที่ผสานรวม ซึ่งจะผสานรวมโหนดสืบทอดเมื่อตั้งค่า mergeDescendants เป็น true นอกจากนี้ยังมีแผนผังความหมายที่ไม่ได้ผสาน ซึ่งไม่ได้ใช้การผสาน แต่จะเก็บโหนดทุกโหนดไว้เหมือนเดิม บริการการช่วยเหลือพิเศษจะใช้ต้นไม้ที่ไม่ได้ผสานรวมและใช้อัลกอริทึมการผสานรวมของตนเอง โดยพิจารณาพร็อพเพอร์ตี้ mergeDescendants เฟรมเวิร์กการทดสอบจะใช้ต้นไม้ที่ผสานโดยค่าเริ่มต้น

คุณตรวจสอบทั้ง 2 แผนผังได้ด้วยเมธอด printToLog() โดยค่าเริ่มต้น และตามตัวอย่างก่อนหน้านี้ ระบบจะบันทึกต้นไม้ที่ผสานไว้ หากต้องการพิมพ์แผนผังที่ไม่ได้ผสานรวมแทน ให้ตั้งค่าพารามิเตอร์ useUnmergedTree ของ Matcher onRoot() เป็น true ดังนี้

composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")

เครื่องมือตรวจสอบเลย์เอาต์ช่วยให้คุณแสดงทั้งแผนผังความหมายที่ผสานและไม่ผสานได้โดยเลือกแผนผังที่ต้องการในตัวกรองมุมมอง ดังนี้

ตัวเลือกมุมมองเครื่องมือตรวจสอบเลย์เอาต์ ซึ่งช่วยให้แสดงทั้งแผนผังความหมายที่ผสานและไม่ผสานได้
รูปที่ 11 ตัวเลือกมุมมองเครื่องมือตรวจสอบเลย์เอาต์ ซึ่งช่วยให้แสดงทั้งแผนผังความหมายที่ผสานและไม่ได้ผสาน

สำหรับแต่ละโหนดในโครงสร้าง เครื่องมือตรวจสอบเลย์เอาต์จะแสดงทั้งความหมายที่ผสานและความหมายที่ตั้งค่าไว้ในโหนดนั้นในแผงพร็อพเพอร์ตี้ ดังนี้

ผสานและตั้งค่าพร็อพเพอร์ตี้ความหมายแล้ว
รูปที่ 12 ผสานและตั้งค่าพร็อพเพอร์ตี้ความหมายแล้ว

โดยค่าเริ่มต้น ตัวจับคู่ในเฟรมเวิร์กการทดสอบจะใช้แผนผังเชิงความหมายที่ผสานแล้ว ด้วยเหตุนี้ คุณจึงโต้ตอบกับ Button ได้โดยจับคู่ข้อความที่แสดงอยู่ภายใน ดังนี้

composeTestRule.onNodeWithText("Like").performClick()

ลบล้างลักษณะการทำงานนี้โดยตั้งค่าพารามิเตอร์ useUnmergedTree ของตัวจับคู่เป็น true เช่นเดียวกับตัวจับคู่ onRoot

ปรับแผนผัง

ดังที่ได้กล่าวไว้ก่อนหน้านี้ คุณสามารถลบล้างหรือล้างพร็อพเพอร์ตี้ความหมายบางอย่าง หรือเปลี่ยนลักษณะการรวมของต้นไม้ได้ ซึ่งจะเกี่ยวข้องเป็นพิเศษเมื่อคุณสร้างคอมโพเนนต์ที่กำหนดเอง หากไม่ได้ตั้งค่าพร็อพเพอร์ตี้และลักษณะการผสานที่ถูกต้อง แอปของคุณอาจเข้าถึงไม่ได้ และการทดสอบอาจทำงานแตกต่างจากที่คุณคาดไว้ หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการทดสอบ โปรดดูคู่มือการทดสอบ