Theo mặc định, hành vi của trình đọc màn hình hỗ trợ tiếp cận trong ứng dụng Compose được triển khai
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ố loại bố cục ứng dụng mà thuật toán không thể xác định
thứ tự đọc thực tế mà không cần thêm gợi ý. Trong ứng dụng dựa trên chế độ xem, bạn có thể
hãy khắc phục những vấn đề đó bằng cách sử dụng thuộc tính traversalBefore
và traversalAfter
.
Kể từ Compose 1.5, Compose cung cấp một API linh hoạt không kém, nhưng với
một mô hình khái niệm mới.
isTraversalGroup
và traversalIndex
là các thuộc tính ngữ nghĩa
cho phép bạn kiểm soát khả năng hỗ trợ tiếp cận và thứ tự lấy nét TalkBack trong các trường hợp mà
thuật toán sắp xếp mặc định là không phù hợp. isTraversalGroup
nhận dạng
các nhóm quan trọng về mặt ngữ nghĩa, trong khi traversalIndex
điều chỉnh thứ tự của
từng yếu tố riêng lẻ trong các nhóm đó. Bạn có thể sử dụng riêng isTraversalGroup
,
hoặc bằng traversalIndex
để tuỳ chỉnh thêm.
Sử dụng isTraversalGroup
và traversalIndex
trong
để kiểm soát thứ tự duyệt qua trình đọc màn hình.
Nhóm các phần tử bằng isTraversalGroup
isTraversalGroup
là thuộc tính boolean xác định liệu ngữ nghĩa
nút là một nhóm truyền tải. Đây là loại nút có chức năng phân phát
làm ranh giới hoặc đường viền để tổ chức các nút con của nút.
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 đó
đượ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àm tâm đ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
. Ứng dụng này phát hành 4 thành phần văn bản. Chiến lược phát hành đĩa đơn
hai phần tử bên trái thuộc về một phần tử CardBox
, còn 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ì chưa có ngữ nghĩa nào được thiết lập nên hành vi mặc định của trình đọc màn hình là để di chuyển các phần tử từ trái sang phải và từ trên xuống dưới. Vì lý do này Theo mặc định, TalkBack sẽ đọc các đoạn câu theo thứ tự không chính xác:
"Câu này bằng" → "Câu này là" → "cột bên trái". → "trên đúng vậy".
Để sắp xếp các mảnh một cách chính xác, hãy sửa đổi đoạn mã gốc để đặ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 thiết lập riêng trên từng CardBox
, nên CardBox
áp dụng các ranh giới khi sắp xếp các phần tử. Trong trường hợp này, bên trái
CardBox
đượ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 bằng" → "cột bên trái". → "Câu này là" → "trên đúng vậy".
Tuỳ chỉnh thêm thứ tự duyệt qua
traversalIndex
là một thuộc tính độ chính xác đơn cho phép bạn tuỳ chỉnh TalkBack
thứ tự duyệt qua. Nếu TalkBack không đủ khả năng để nhóm các phần tử lại với nhau
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ị
traversalIndex
thấp hơn sẽ được ưu tiên trước. - Có thể là tích cực hoặc tiêu cực.
- Giá trị mặc định là
0f
. - Chỉ ảnh hưởng đến các nút có thể làm tâm điểm của trình đọc màn hình, chẳng hạn như các phần tử trên màn hình như
văn bản hoặc nút. Ví dụ: chỉ đặt
traversalIndex
trên một cột sẽ không có hiệu lực, trừ phi cột này cũng đã đặtisTraversalGroup
.
Ví dụ sau đây trình bày cách sử dụng traversalIndex
và
isTraversalGroup
cùng nhau.
Ví dụ: Mặt đồng hồ dạng ngang
Mặt đồng hồ là trường hợp phổ biến khi thứ tự truyền tải tiêu chuẩn không cơ quan. Ví dụ trong phần này là bộ chọn giờ mà người dùng có thể chuyển tải thông qua các số trên mặt đồng hồ và chọn các chữ số cho giờ và phút vị trí.
Trong đoạn mã đơn giản sau, có một CircularLayout
trong đó 12
các số được vẽ, bắt đầu từ số 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()) } }
Do mặt đồng hồ không được đọc hợp lý theo mặc định từ trái sang phải và từ trên xuống dưới, TalkBack sẽ đọc các số theo thứ tự. Để khắc phục 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 CircularLayout
làm
nhóm truyền tải và đặt isTraversalGroup = true
. Sau đó, khi mỗi văn bản trên đồng hồ
được vẽ vào bố cục, đặt traversalIndex
tương ứng của nó thành bộ đếm
giá trị.
Do giá trị bộ đếm liên tục tăng, nên mỗi giá trị xung nhịp
traversalIndex
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.
Theo cách này, thứ tự mà TalkBack đọc các âm thanh đó sẽ được đặt. Giờ đây, các con số
bên trong CircularLayout
sẽ được đọc theo thứ tự dự kiến.
Vì traversalIndexes
đã được đặt chỉ liên quan đến các giá trị khác
chỉ mục trong cùng một nhóm, phần còn lại của thứ tự màn hình sẽ được
không bị ảnh hưởng. Nói cách khác, những thay đổi về ngữ nghĩa được thể hiện trong mã trước đó
đoạn mã chỉ sửa đổi thứ tự trong mặt đồng hồ có
Đã đặt isTraversalGroup = true
.
Lưu ý rằng nếu không đặt ngữ nghĩa CircularLayout's
thành isTraversalGroup =
true
, các thay đổi đối với traversalIndex
vẫn được áp dụng. Tuy nhiên, nếu không có
CircularLayout
để ràng buộc các thành phần này, 12 chữ số của mặt đồng hồ sẽ được đọc
là 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ồ sẽ được đọc sau tất cả các phần tử 0f
khác.
Ví dụ: Tuỳ chỉnh thứ tự duyệt qua cho nút hành động nổi
Trong ví dụ này, traversalIndex
và isTraversalGroup
kiểm soát
thứ tự duyệt của nút hành động nổi trong Material Design (FAB). Cơ sở
của ví dụ này là bố cục sau:
Theo mặc định, bố cục trong ví dụ này có thứ tự TalkBack sau:
Thanh ứng dụng trên cùng → Văn bản mẫu từ 0 đến 6 → nút hành động nổi (FAB) → Dưới cùng Thanh ứng dụng
Trước tiên, bạn nên đặt trình đọc màn hình tập trung vào nút hành động nổi. Để đặt một
traversalIndex
trên một phần tử Material như FAB, hãy làm như sau:
@Composable fun FloatingBox() { Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) { FloatingActionButton(onClick = {}) { Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon") } } }
Trong đoạn mã này, việc tạo một hộp có
Đã đặt isTraversalGroup
thành true
và đặt traversalIndex
trên cùng một hộp
(-1f
thấp hơn giá trị mặc định của 0f
) có nghĩa là hộp thả nổi
xuất hiện trước mọi thành phần khác trên màn hình.
Tiếp theo, bạn có thể đặt hộp nổi và các thành phần khác vào một scaffold (giàn giáo). triển khai bố cục Material Design:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun ColumnWithFABFirstDemo() { Scaffold( topBar = { TopAppBar(title = { Text("Top App Bar") }) }, floatingActionButtonPosition = FabPosition.End, floatingActionButton = { FloatingBox() }, content = { padding -> ContentColumn(padding = padding) }, bottomBar = { BottomAppBar { Text("Bottom App Bar") } } ) }
TalkBack tương tác với các phần tử theo thứ tự sau:
FAB → Thanh ứng dụng trên cùng → Văn bản mẫu từ 0 đến 6 → Thanh ứng dụng dưới cùng
Tài nguyên khác
- Hỗ trợ tiếp cận: Các khái niệm và khái niệm cơ bản những kỹ thuật phổ biến đối với mọi hoạt động phát triển ứng dụng Android
- Xây dựng ứng dụng dễ tiếp cận: Các bước quan trọng bạn có thể thực hiện để tăng khả năng hỗ trợ tiếp cận cho ứng dụng
- Các nguyên tắc giúp cải thiện ứng dụng hỗ trợ tiếp cận: Các nguyên tắc chính để cần lưu ý khi tìm cách làm cho ứng dụng dễ tiếp cận hơn
- Kiểm thử khả năng hỗ trợ tiếp cận: Kiểm thử các nguyên tắc và công cụ hỗ trợ tiếp cận của Android