แก้ไขลําดับการส่งผ่าน

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

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

ใช้ isTraversalGroup และ traversalIndex ในแอปเพื่อควบคุมลำดับการส่งผ่านของโปรแกรมอ่านหน้าจอ

จัดกลุ่มองค์ประกอบสำหรับการไปยังส่วนต่างๆ

isTraversalGroup เป็นพร็อพเพอร์ตี้บูลีนที่กำหนดว่าโหนด semantics เป็นกลุ่มการข้ามผ่านหรือไม่ โหนดประเภทนี้มีหน้าที่ทำหน้าที่เป็นขอบเขตหรือเส้นขอบในการจัดระเบียบโหนดย่อย

การตั้งค่า isTraversalGroup = true ในโหนดหมายความว่าระบบจะเข้าชมโหนดย่อยทั้งหมดของโหนดนั้นก่อนที่จะย้ายไปยังองค์ประกอบอื่นๆ คุณสามารถตั้งค่า isTraversalGroup ในโหนดที่โฟกัสได้ซึ่งไม่ใช่โปรแกรมอ่านหน้าจอ เช่น คอลัมน์ แถว หรือช่อง

ตัวอย่างต่อไปนี้ใช้ isTraversalGroup โดยจะแสดงองค์ประกอบของข้อความ 4 รายการ องค์ประกอบ 2 รายการทางด้านซ้ายเป็นขององค์ประกอบ CardBox รายการหนึ่ง ส่วนองค์ประกอบ 2 รายการทางด้านขวาเป็นขององค์ประกอบ CardBox อีกรายการหนึ่ง

// CardBox() function takes in top and bottom sample text.
@Composable
fun CardBox(
    topSampleText: String,
    bottomSampleText: String,
    modifier: Modifier = Modifier
) {
    Box(modifier) {
        Column {
            Text(topSampleText)
            Text(bottomSampleText)
        }
    }
}

@Composable
fun TraversalGroupDemo() {
    val topSampleText1 = "This sentence is in "
    val bottomSampleText1 = "the left column."
    val topSampleText2 = "This sentence is "
    val bottomSampleText2 = "on the right."
    Row {
        CardBox(
            topSampleText1,
            bottomSampleText1
        )
        CardBox(
            topSampleText2,
            bottomSampleText2
        )
    }
}

โค้ดจะสร้างเอาต์พุตที่คล้ายกับต่อไปนี้

เลย์เอาต์ที่มีข้อความ 2 คอลัมน์ โดยคอลัมน์ด้านซ้ายเขียนว่า "ประโยคนี้อยู่ในคอลัมน์ด้านซ้าย" และคอลัมน์ด้านขวาเขียนว่า "ประโยคนี้อยู่ทางด้านขวา"
รูปที่ 1 เลย์เอาต์ที่มี 2 ประโยค (ประโยคหนึ่งในคอลัมน์ซ้ายและอีกประโยคหนึ่งในคอลัมน์ขวา)

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

"ประโยคนี้อยู่ใน" → "ประโยคนี้คือ" → "คอลัมน์ด้านซ้าย" → "ทางด้านขวา"

หากต้องการจัดลำดับข้อมูลโค้ดให้ถูกต้อง ให้แก้ไขข้อมูลโค้ดเดิมเพื่อตั้งค่า isTraversalGroup เป็น true ดังนี้

@Composable
fun TraversalGroupDemo2() {
    val topSampleText1 = "This sentence is in "
    val bottomSampleText1 = "the left column."
    val topSampleText2 = "This sentence is"
    val bottomSampleText2 = "on the right."
    Row {
        CardBox(
//      1,
            topSampleText1,
            bottomSampleText1,
            Modifier.semantics { isTraversalGroup = true }
        )
        CardBox(
//      2,
            topSampleText2,
            bottomSampleText2,
            Modifier.semantics { isTraversalGroup = true }
        )
    }
}

เนื่องจากมีการตั้งค่า isTraversalGroup ไว้ใน CardBox แต่ละรายการโดยเฉพาะ ขอบเขตของ CardBox จึงมีผลเมื่อจัดเรียงองค์ประกอบ ในกรณีนี้ ระบบจะอ่าน CardBox ด้านซ้ายก่อน ตามด้วย CardBox ด้านขวา

ตอนนี้ TalkBack จะอ่านส่วนต่างๆ ของประโยคตามลำดับที่ถูกต้อง ดังนี้

"This sentence is in" → "the left column." → "This sentence is" → "on the right."

ปรับแต่งลำดับการส่งผ่าน

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

พร็อพเพอร์ตี้ traversalIndex มีลักษณะดังนี้

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

ตัวอย่างต่อไปนี้แสดงวิธีใช้ traversalIndex และ isTraversalGroup ร่วมกัน

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

หน้าปัดนาฬิกาที่มีเครื่องมือเลือกเวลาอยู่ด้านบน
รูปที่ 2 รูปภาพหน้าปัดนาฬิกา

ในข้อมูลโค้ดที่ลดความซับซ้อนลงต่อไปนี้ มี CircularLayout ที่มีตัวเลข 12 ตัว โดยเริ่มจาก 12 และวนตามเข็มนาฬิการอบวงกลม

@Composable
fun ClockFaceDemo() {
    CircularLayout {
        repeat(12) { hour ->
            ClockText(hour)
        }
    }
}

@Composable
private fun ClockText(value: Int) {
    Box(modifier = Modifier) {
        Text((if (value == 0) 12 else value).toString())
    }
}

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

@Composable
fun ClockFaceDemo() {
    CircularLayout(Modifier.semantics { isTraversalGroup = true }) {
        repeat(12) { hour ->
            ClockText(hour)
        }
    }
}

@Composable
private fun ClockText(value: Int) {
    Box(modifier = Modifier.semantics { this.traversalIndex = value.toFloat() }) {
        Text((if (value == 0) 12 else value).toString())
    }
}

หากต้องการตั้งค่าลำดับการส่งผ่านอย่างถูกต้อง ให้กำหนด CircularLayout เป็นกลุ่มการส่งผ่านก่อน แล้วตั้งค่า isTraversalGroup = true จากนั้นเมื่อวาดข้อความนาฬิกาแต่ละรายการลงในเลย์เอาต์ ให้ตั้งค่า traversalIndex ที่เกี่ยวข้องเป็นค่าตัวนับ

เนื่องจากค่าตัวนับเพิ่มขึ้นอย่างต่อเนื่อง traversalIndex ของค่านาฬิกาแต่ละค่าจึงมีขนาดใหญ่ขึ้นเมื่อมีการเพิ่มตัวเลขลงในหน้าจอ โดยค่านาฬิกา 0 มี traversalIndex เป็น 0 และค่านาฬิกา 1 มี traversalIndex เป็น 1 วิธีนี้จะกำหนดลำดับที่ TalkBack อ่าน ตอนนี้ตัวเลขภายใน CircularLayout จะอ่านตามลำดับที่คาดไว้

เนื่องจาก traversalIndexes ที่ตั้งค่าไว้จะสัมพันธ์กับดัชนีอื่นๆ ภายในกลุ่มเดียวกันเท่านั้น ระบบจึงคงลำดับหน้าจอที่เหลือไว้ กล่าวคือ การเปลี่ยนแปลงเชิงความหมายที่แสดงในข้อมูลโค้ดก่อนหน้าจะแก้ไขเฉพาะการจัดลำดับภายในหน้าปัดนาฬิกาที่มีการตั้งค่า isTraversalGroup = true ไว้เท่านั้น

โปรดทราบว่าแม้จะไม่ได้ตั้งค่าความหมายของ CircularLayout's เป็น isTraversalGroup = true การเปลี่ยนแปลง traversalIndex ก็จะยังมีผลอยู่ อย่างไรก็ตาม หากไม่มี CircularLayout เพื่อเชื่อมโยง ตัวเลข 12 ตัวของหน้าปัดนาฬิกาจะอ่านเป็นลำดับสุดท้าย หลังจากที่ได้เข้าชมองค์ประกอบอื่นๆ ทั้งหมดบนหน้าจอแล้ว ซึ่งเกิดขึ้นเนื่องจากองค์ประกอบอื่นๆ ทั้งหมดมี traversalIndex เริ่มต้นเป็น 0f และระบบจะอ่านองค์ประกอบของข้อความนาฬิกาหลังจากองค์ประกอบ 0f อื่นๆ ทั้งหมด

ข้อควรพิจารณาเกี่ยวกับ API

โปรดคำนึงถึงสิ่งต่อไปนี้เมื่อใช้ Traversal API

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