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 thành phần 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 đó là 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 ảnh hưởng đến thứ tự duyệt qua các dịch vụ hỗ trợ tiếp cận trong các 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ề ngữ nghĩa cần được 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ể chỉ sử dụng isTraversalGroup
để cho biết 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ự di chuyển của trình đọc màn hình.
Nhóm các phần tử để duyệt qua
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 duyệt qua 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ả các phần tử con của nút đó sẽ đượ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
. Phương thức 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 sẽ tạo ra kết quả tương tự như sau:

Vì chưa đặt ngữ nghĩa nào, nên hành vi mặc định của trình đọc màn hình là di chuyển 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 mảnh câu theo thứ tự không chính xác:
"Câu này nằm trong" → "Câu này là" → "cột bên trái." → "ở bên phải".
Để sắp xếp các mảnh một cách chính xác, 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 trên mỗi CardBox
, nên các 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.
Giờ đây, TalkBack sẽ đọc các mảnh câu theo đúng thứ tự:
"Câu này nằm trong" → "cột bên trái." → "Câu này là" → "ở 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 TalkBack. Nếu việc nhóm các phần tử lại với nhau không đủ để TalkBack hoạt động chính xác, hãy sử dụng traversalIndex
kết hợp 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ị
traversalIndex
thấp hơn sẽ được ưu tiên trước. - Có thể là dương hoặc âm.
- Giá trị mặc định là
0f
. - Để chỉ mục di chuyển ảnh hưởng đến hành vi di chuyển, 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.
- Việc chỉ đặt
traversalIndex
trên, ví dụ:Column
sẽ không có hiệu lực, trừ phi cột đó cũng được đặtisTraversalGroup
.
- Việc chỉ đặt
Ví dụ sau đây cho thấy cách bạn có thể sử dụng traversalIndex
và isTraversalGroup
cùng nhau.
Mặt đồng hồ là một trường hợp phổ biến mà thứ tự duyệt qua tiêu chuẩn không hoạt động. Ví dụ trong phần này là bộ chọn giờ, trong đó người dùng có thể di chuyển qua các số trên mặt đồng hồ và chọn chữ số cho các ô 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 từ 12 và di chuyển theo chiều kim đồng hồ xung 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ự mặc định từ trái sang phải và từ trên xuống dưới một cách hợp lý, nên TalkBack đọ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()) } }
Để thiết lập đúng thứ tự duyệt qua, trước tiên, hãy tạo CircularLayout
thành một nhóm duyệt qua và thiết lập 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 lên, 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, TalkBack sẽ thiết lập thứ tự đọc các mục đó. Bây giờ, các số trong CircularLayout
sẽ được đọc theo thứ tự dự kiến.
Vì traversalIndexes
đã được đặt chỉ tương ứng với các chỉ mục khác trong cùng một nhóm, nên phần còn lại của thứ tự màn hình đã được giữ nguyên. Nói cách khác, các thay đổi ngữ nghĩa hiển thị 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
, các thay đổi về traversalIndex
vẫn sẽ áp dụng. Tuy nhiên, nếu không có CircularLayout
để liên kết các thành phần này, 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 duyệt qua:
- Bạn nên đặt
isTraversalGroup = true
trên phần tử mẹ chứa các phần tử được nhóm. - Bạn nên đặt
traversalIndex
trê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 điều tra đều ở cùng cấp độ
zIndex
, vì điều đó cũng ảnh hưởng đến ngữ nghĩa và thứ tự truy cập. - Đảm bảo không hợp nhất ngữ nghĩa 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 duyệt qua đượ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