Thứ tự duyệt qua là thứ tự mà các dịch vụ hỗ trợ tiếp cận di chuyển qua các phần tử trên giao diện người dùng. Trong ứng dụng Compose, các phần tử được sắp xếp theo thứ tự đọc dự kiến, thường là từ trái sang phải, sau đó từ trên xuống dưới. Tuy nhiên, có một số trường hợp Compose có thể cần thêm gợi ý để xác định thứ tự đọc chính xác.
isTraversalGroup và traversalIndex là các thuộc tính ngữ nghĩa cho phép bạn tác động đến thứ tự duyệt qua cho các dịch vụ hỗ trợ tiếp cận trong trường hợp thuật toán sắp xếp mặc định của Compose không đủ. isTraversalGroup xác định các nhóm quan trọng về mặt ngữ nghĩa cần tuỳ chỉnh, trong khi traversalIndex điều chỉnh thứ tự của từng phần tử trong các nhóm đó.
Bạn có thể sử dụng riêng isTraversalGroup để biểu thị rằng tất cả các phần tử trong một nhóm phải được chọn cùng nhau hoặc với traversalIndex để tuỳ chỉnh thêm.
Sử dụng isTraversalGroup và traversalIndex trong ứng dụng để kiểm soát thứ tự duyệt qua của trình đọc màn hình.
Nhóm các phần tử để truyền tải
isTraversalGroup là một thuộc tính boolean xác định xem nút ngữ nghĩa có phải là một nhóm truyền tải hay không. Loại nút này có chức năng đóng vai trò là ranh giới hoặc đường viền trong việc sắp xếp các nút con.
Việc đặt isTraversalGroup = true trên một nút có nghĩa là tất cả phần tử con của nút đó đều được truy cập trước khi chuyển sang các phần tử khác. Bạn có thể đặt isTraversalGroup trên các nút không thể lấy tiêu điểm của trình đọc màn hình, chẳng hạn như cột, hàng hoặc hộp.
Ví dụ sau đây sử dụng isTraversalGroup. Hàm này phát ra 4 phần tử văn bản. Hai phần tử bên trái thuộc về một phần tử CardBox, trong khi hai phần tử bên phải thuộc về một phần tử CardBox khác:
// 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 ) } }
Mã này tạo ra kết quả tương tự như sau:
Vì không có ngữ nghĩa nào được đặt, nên hành vi mặc định của trình đọc màn hình là duyệt qua các phần tử từ trái sang phải và từ trên xuống dưới. Do chế độ mặc định này, TalkBack đọc các đoạn câu theo thứ tự sai:
"Câu này nằm trong" → "Câu này nằm trong" → "cột bên trái". → "ở bên phải".
Để sắp xếp các đoạn mã theo đúng thứ tự, hãy sửa đổi đoạn mã ban đầu để đặt isTraversalGroup thành 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 } ) } }
Vì isTraversalGroup được đặt riêng cho từng CardBox, nên ranh giới CardBox sẽ áp dụng khi sắp xếp các phần tử của chúng. Trong trường hợp này, CardBox bên trái được đọc trước, sau đó là CardBox bên phải.
Bây giờ, TalkBack sẽ đọc các đoạn câu theo đúng thứ tự:
"Câu này nằm ở" → "cột bên trái". → "Câu này" → "ở bên phải".
Tuỳ chỉnh thứ tự duyệt qua
traversalIndex là một thuộc tính float cho phép bạn tuỳ chỉnh thứ tự duyệt qua của TalkBack. Nếu việc nhóm các phần tử lại với nhau là chưa đủ để TalkBack hoạt động chính xác, hãy sử dụng traversalIndex cùng với isTraversalGroup để tuỳ chỉnh thêm thứ tự của trình đọc màn hình.
Thuộc tính traversalIndex có các đặc điểm sau:
- Các phần tử có giá trị
traversalIndexthấp hơn sẽ được ưu tiên trước. - Có thể là số dương hoặc số âm.
- Giá trị mặc định là
0f. - Để chỉ mục truyền tải ảnh hưởng đến hành vi truyền tải, bạn phải đặt chỉ mục này trên một thành phần mà các dịch vụ hỗ trợ tiếp cận có thể chọn và lấy tiêu điểm, chẳng hạn như các thành phần trên màn hình như văn bản hoặc nút.
- Ví dụ: việc chỉ đặt
traversalIndextrênColumnsẽ không có hiệu lực, trừ phi cột cũng được đặtisTraversalGroup.
- Ví dụ: việc chỉ đặt
Ví dụ sau đây cho thấy cách bạn có thể sử dụng kết hợp traversalIndex và isTraversalGroup.
Mặt đồng hồ là một trường hợp phổ biến mà thứ tự duyệt qua chuẩn không hoạt động. Ví dụ trong phần này là bộ chọn thời gian, trong đó người dùng có thể duyệt qua các số trên mặt đồng hồ và chọn các chữ số cho ô giờ và phút.
Trong đoạn mã đơn giản sau đây, có một CircularLayout trong đó 12 số được vẽ, bắt đầu bằng 12 và di chuyển theo chiều kim đồng hồ quanh vòng tròn:
@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()) } }
Vì mặt đồng hồ không được đọc theo thứ tự từ trái sang phải và từ trên xuống dưới, nên TalkBack sẽ đọc các số không theo thứ tự. Để khắc phục vấn đề này, hãy sử dụng giá trị bộ đếm tăng dần, như trong đoạn mã sau:
@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()) } }
Để đặt thứ tự duyệt qua đúng cách, trước tiên, hãy đặt CircularLayout thành một nhóm duyệt qua và đặt isTraversalGroup = true. Sau đó, khi mỗi văn bản đồng hồ được vẽ lên bố cục, hãy đặt traversalIndex tương ứng thành giá trị bộ đếm.
Vì giá trị bộ đếm liên tục tăng, nên traversalIndex của mỗi giá trị đồng hồ sẽ lớn hơn khi các số được thêm vào màn hình – giá trị đồng hồ 0 có traversalIndex là 0 và giá trị đồng hồ 1 có traversalIndex là 1.
Bằng cách này, thứ tự mà TalkBack đọc các thành phần sẽ được thiết lập. Bây giờ, các số bên trong CircularLayout được đọc theo thứ tự dự kiến.
Vì traversalIndexes đã đặt chỉ liên quan đến các chỉ mục khác trong cùng một nhóm, nên thứ tự còn lại của màn hình vẫn được giữ nguyên. Nói cách khác, các thay đổi về ngữ nghĩa được trình bày trong đoạn mã trước chỉ sửa đổi thứ tự trong mặt đồng hồ đã đặt isTraversalGroup = true.
Xin lưu ý rằng nếu không đặt ngữ nghĩa CircularLayout's thành isTraversalGroup =
true, thì các thay đổi về traversalIndex vẫn được áp dụng. Tuy nhiên, nếu không có CircularLayout để liên kết, thì 12 chữ số của mặt đồng hồ sẽ được đọc sau cùng, sau khi tất cả các thành phần khác trên màn hình đã được truy cập. Điều này xảy ra vì tất cả các phần tử khác đều có traversalIndex mặc định là 0f và các phần tử văn bản đồng hồ được đọc sau tất cả các phần tử 0f khác.
Những điều cần cân nhắc về API
Hãy cân nhắc những điều sau khi sử dụng API truyền tải:
- Bạn nên đặt
isTraversalGroup = truetrên thành phần mẹ chứa các thành phần được nhóm. - Bạn nên đặt
traversalIndextrên một thành phần con chứa ngữ nghĩa và sẽ được các dịch vụ hỗ trợ tiếp cận chọn. - Đảm bảo rằng tất cả các phần tử bạn đang kiểm tra đều ở cùng một cấp
zIndex, vì điều đó cũng ảnh hưởng đến ngữ nghĩa và thứ tự duyệt qua. - Đảm bảo không có ngữ nghĩa nào được hợp nhất một cách không cần thiết, vì điều này có thể ảnh hưởng đến các thành phần mà chỉ mục truyền tải được áp dụng.
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Hỗ trợ tiếp cận trong Compose
- [Material Design 2 trong Compose][19]
- Kiểm thử bố cục Compose