Thành phần kết hợp mô tả giao diện người dùng của ứng dụng và được tạo ra bằng cách chạy thành phần kết hợp. Cấu trúc là một cấu trúc cây bao gồm các thành phần kết hợp mô tả giao diện người dùng.
Bên cạnh Cấu trúc, có một cây song song, gọi là ngữ nghĩa cây. Cây này mô tả giao diện người dùng theo một cách khác dễ hiểu đối với các dịch vụ Hỗ trợ tiếp cận và cho Thử nghiệm khung. Các dịch vụ hỗ trợ tiếp cận sử dụng cây này để mô tả ứng dụng cho người dùng một nhu cầu cụ thể. Khung kiểm thử sử dụng cây để tương tác với ứng dụng của bạn và khẳng định về điều đó. Cây Ngữ nghĩa không chứa thông tin về cách vẽ các thành phần kết hợp, nhưng có chứa thông tin về ý nghĩa ngữ nghĩa của các thành phần kết hợp.
![Một hệ phân cấp giao diện người dùng điển hình và cây ngữ nghĩa](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-ui-tree.png?authuser=6&hl=vi)
Nếu ứng dụng của bạn bao gồm các thành phần kết hợp và đối tượng sửa đổi từ nền tảng Compose và thư viện tài liệu, thì cây ngữ nghĩa sẽ được tự động điền và tạo cho bạn. Tuy nhiên, khi thêm thành phần kết hợp tuỳ chỉnh cấp thấp, bạn phải để cung cấp ngữ nghĩa theo cách thủ công. Cũng có thể có các trường hợp mà cây của bạn không thể hiện chính xác hoặc đầy đủ ý nghĩa của các phần tử trên màn hình, trong trường hợp đó, bạn có thể điều chỉnh cây.
Xem xét ví dụ về thành phần kết hợp lịch tuỳ chỉnh này:
![Một thành phần kết hợp lịch tuỳ chỉnh với các phần tử ngày có thể chọn](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-calendar.png?authuser=6&hl=vi)
Trong ví dụ này, toàn bộ lịch được triển khai dưới dạng thành phần kết hợp cấp thấp, bằng cách sử dụng Layout
có thể kết hợp và vẽ trực tiếp vào Canvas
.
Nếu bạn không làm gì khác, các dịch vụ hỗ trợ tiếp cận sẽ không nhận đủ dữ liệu
thông tin về nội dung của thành phần kết hợp và lựa chọn của người dùng trong
lịch. Ví dụ: nếu người dùng nhấp vào ngày chứa 17, khung hỗ trợ tiếp cận sẽ chỉ nhận được thông tin mô tả cho toàn bộ quyền kiểm soát lịch. Trong trường hợp này, dịch vụ hỗ trợ tiếp cận TalkBack sẽ
thông báo "Lịch" hoặc chỉ tốt hơn một chút là "Lịch tháng Tư" và người dùng
sẽ không biết chọn ngày nào. Để thành phần kết hợp này trở nên phù hợp hơn
có thể truy cập được, bạn sẽ cần thêm thông tin ngữ nghĩa theo cách thủ công.
Thuộc tính ngữ nghĩa
Tất cả các nút trong cây giao diện người dùng có một số ý nghĩa ngữ nghĩa đều có một nút song song trong cây Ngữ nghĩa. Nút trong cây Ngữ nghĩa chứa các thuộc tính truyền tải ý nghĩa của thành phần kết hợp tương ứng. Ví dụ: Text
thành phần kết hợp chứa một thuộc tính ngữ nghĩa text
, vì đó là ý nghĩa của
thành phần kết hợp đó. Icon
chứa thuộc tính contentDescription
(nếu được đặt bởi
nhà phát triển) truyền tải văn bản ý nghĩa của Icon
.
Các thành phần kết hợp và đối tượng sửa đổi được xây dựng dựa trên nền tảng Compose
thư viện đã đặt các thuộc tính có liên quan cho bạn. Đặt (không bắt buộc)
hoặc tự ghi đè các thuộc tính bằng semantics
và
Đối tượng sửa đổi clearAndSetSemantics
. Ví dụ: thêm tùy chỉnh
hành động hỗ trợ tiếp cận vào một nút, cung cấp một trạng thái thay thế
mô tả cho một phần tử bật/tắt được hoặc cho biết rằng một văn bản nhất định
thành phần kết hợp phải được coi là tiêu đề.
Để trực quan hoá cây Ngữ nghĩa, hãy dùng Công cụ Layout Inspector hoặc dùng
Phương thức printToLog()
bên trong kiểm thử. Thao tác này sẽ in dòng
Cây ngữ nghĩa trong Logcat.
class MyComposeTest { @get:Rule val composeTestRule = createComposeRule() @Test fun MyTest() { // Start the app composeTestRule.setContent { MyTheme { Text("Hello world!") } } // Log the full semantics tree composeTestRule.onRoot().printToLog("MY TAG") } }
Kết quả của lần kiểm thử này sẽ là:
Printing with useUnmergedTree = 'false'
Node #1 at (l=0.0, t=63.0, r=221.0, b=120.0)px
|-Node #2 at (l=0.0, t=63.0, r=221.0, b=120.0)px
Text = '[Hello world!]'
Actions = [GetTextLayoutResult]
Cân nhắc cách các thuộc tính ngữ nghĩa truyền tải ý nghĩa của một thành phần kết hợp. Hãy cân nhắc sử dụng
Switch
. Đây là giao diện mà người dùng thấy:
![](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-switches.png?authuser=6&hl=vi)
Để mô tả ý nghĩa của phần tử này, bạn có thể nói như sau: "This là một Switch, một phần tử có thể bật/tắt ở chế độ "On" (Bật) trạng thái. Bạn có thể nhấp vào đó tương tác với nó."
Đây chính xác là những thuộc tính ngữ nghĩa được dùng. Nút ngữ nghĩa của phần tử Chuyển đổi này chứa các thuộc tính sau, như được minh hoạ bằng Layout Inspector (Trình kiểm tra bố cục):
![Layout Inspector cho thấy các thuộc tính ngữ nghĩa của thành phần kết hợp Switch (Chuyển đổi)](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-layout-inspector-switch.png?authuser=6&hl=vi)
Role
cho biết loại phần tử. StateDescription
mô tả cách
"Bật" trạng thái cần được tham chiếu. Theo mặc định, đây là phiên bản được bản địa hoá của
từ "Bật", nhưng có thể làm điều này cụ thể hơn (ví dụ: "Đã bật") dựa trên
vào ngữ cảnh. ToggleableState
là trạng thái hiện tại của Nút chuyển. Chiến lược phát hành đĩa đơn
Thuộc tính OnClick
tham chiếu phương thức dùng để tương tác với phần tử này. Để
danh sách đầy đủ các thuộc tính ngữ nghĩa, hãy xem SemanticsProperties
. Để biết danh sách đầy đủ các Hành động hỗ trợ tiếp cận, hãy xem đối tượng SemanticsActions
.
Việc theo dõi các thuộc tính ngữ nghĩa của từng thành phần kết hợp trong ứng dụng của bạn sẽ mở ra rất nhiều khả năng mạnh mẽ. Một số ví dụ:
- TalkBack sử dụng các thuộc tính để đọc to nội dung hiển thị trên màn hình và cho phép người dùng tương tác mượt mà với nó. Đối với thành phần kết hợp Switch (Chuyển đổi), TalkBack có thể nói: "Bật; Chuyển đổi; nhấn đúp để bật/tắt". Người dùng có thể nhấn đúp vào để tắt Nút chuyển.
-
Khung kiểm thử sử dụng các thuộc tính để tìm nút, tương tác với chúng và đưa ra xác nhận. Một chương trình kiểm thử mẫu cho Nút chuyển có thể là:
val mySwitch = SemanticsMatcher.expectValue( SemanticsProperties.Role, Role.Switch ) composeTestRule.onNode(mySwitch) .performClick() .assertIsOff()
Cây Ngữ nghĩa đã hợp nhất và chưa hợp nhất
Như đã đề cập trước đó, mỗi thành phần kết hợp trong cây Giao diện người dùng có thể không có hoặc có nhiều thuộc tính ngữ nghĩa. Khi một thành phần kết hợp chưa đặt thuộc tính ngữ nghĩa, không được đưa vào cây Ngữ nghĩa. Bằng cách đó, cây Ngữ nghĩa chỉ chứa các nút thực sự chứa ý nghĩa ngữ nghĩa. Tuy nhiên, đôi khi, để truyền đạt ý nghĩa chính xác của nội dung hiển thị trên màn hình, bạn cũng nên hợp nhất một số cây phụ của nút và coi chúng là một. Bằng cách đó bạn có thể giải thích về toàn bộ tập hợp nút, thay vì xử lý từng nút nút con riêng lẻ. Theo quy tắc chung, mỗi nút trong cây này đại diện cho một phần tử có thể lấy tiêu điểm khi sử dụng các dịch vụ Hỗ trợ tiếp cận.
Ví dụ về thành phần kết hợp đó là Button
. Bạn có thể nêu lý do về một nút
dưới dạng một phần tử, mặc dù phần tử này có thể chứa nhiều nút con:
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
Trong cây Ngữ nghĩa, các thuộc tính của các thành phần con của nút được hợp nhất, và nút này được biểu thị dưới dạng một nút lá đơn trên cây:
![Biểu diễn ngữ nghĩa một lá hợp nhất](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-merged-single-leaf.png?authuser=6&hl=vi)
Các thành phần kết hợp và đối tượng sửa đổi có thể cho biết rằng chúng muốn hợp nhất các thuộc tính ngữ nghĩa của phần tử con bằng cách gọi Modifier.semantics
(mergeDescendants = true) {}
. Việc đặt thuộc tính này thành true
cho biết rằng thuộc tính ngữ nghĩa cần được hợp nhất. Trong ví dụ về Button
, Button
sử dụng đối tượng sửa đổi clickable
trong nội bộ bao gồm
Đối tượng sửa đổi semantics
. Do đó, các nút con của nút này đã được hợp nhất.
Hãy đọc tài liệu về khả năng hỗ trợ tiếp cận để tìm hiểu thêm về thời điểm bạn nên thay đổi
hành vi hợp nhất trong thành phần kết hợp.
Một số đối tượng sửa đổi và thành phần kết hợp trong Thư viện nền tảng và thư viện Material Compose có bộ thuộc tính này. Ví dụ: đối tượng sửa đổi clickable
và toggleable
sẽ tự động hợp nhất các phần tử con. Ngoài ra, ListItem
hoạt động tương ứng sẽ hợp nhất các thành phần con.
Kiểm tra cây cối
Thực tế, cây ngữ nghĩa là hai cây khác nhau. Có một ngữ nghĩa hợp nhất
cây này hợp nhất các nút con khi bạn đặt mergeDescendants
thành true
.
Ngoài ra còn có cây Ngữ nghĩa chưa hợp nhất không áp dụng hợp nhất, nhưng
giữ nguyên mọi nút. Các dịch vụ hỗ trợ tiếp cận dùng cây chưa hợp nhất và áp dụng
các thuật toán hợp nhất riêng của chúng, xem xét mergeDescendants
thuộc tính này. Theo mặc định, khung kiểm thử sử dụng cây đã hợp nhất.
Bạn có thể kiểm tra cả hai cây bằng phương thức printToLog()
. Theo mặc định và như trong
các ví dụ trước đó, cây hợp nhất sẽ được ghi lại. Để in cây chưa hợp nhất
thay vào đó, hãy đặt tham số useUnmergedTree
của trình so khớp onRoot()
thành
true
:
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
Layout Inspector cho phép bạn hiển thị cả Ngữ nghĩa hợp nhất và chưa hợp nhất bằng cách chọn cây ưa thích trong bộ lọc chế độ xem:
![Các tuỳ chọn khung hiển thị của Layout Inspector, cho phép hiển thị cả cây Ngữ nghĩa hợp nhất và chưa hợp nhất](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-layout-inspector-menu.png?authuser=6&hl=vi)
Đối với mỗi nút trong cây của bạn, Layout Inspector hiển thị cả Ngữ nghĩa hợp nhất và Ngữ nghĩa chưa hợp nhất đã đặt trên nút đó trong bảng thuộc tính:
![Hợp nhất và đặt thuộc tính ngữ nghĩa](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-merged-and-set.png?authuser=6&hl=vi)
Theo mặc định, các trình so khớp trong Khung kiểm thử sẽ sử dụng cây Ngữ nghĩa đã hợp nhất.
Đó là lý do bạn có thể tương tác với Button
bằng cách so khớp văn bản bên trong
nó:
composeTestRule.onNodeWithText("Like").performClick()
Ghi đè hành vi này bằng cách đặt tham số useUnmergedTree
của
so khớp với true
, giống như với trình so khớp onRoot
.
Hành vi hợp nhất
Khi một thành phần kết hợp cho biết rằng các thành phần con của nó nên được hợp nhất, thì việc hợp nhất này xảy ra chính xác như thế nào?
Mỗi thuộc tính ngữ nghĩa có một chiến lược hợp nhất xác định. Ví dụ:
Thuộc tính ContentDescription
thêm tất cả các giá trị con trong ContentDescription vào một
danh sách. Kiểm tra chiến lược hợp nhất của một thuộc tính ngữ nghĩa bằng cách kiểm tra
Triển khai mergePolicy
trong SemanticsProperties.kt
. Cơ sở lưu trú có thể
lấy giá trị mẹ hoặc giá trị con, hợp nhất các giá trị thành một danh sách hoặc
chuỗi, hoàn toàn không cho phép hợp nhất và gửi một ngoại lệ hoặc bất kỳ
hợp nhất tuỳ chỉnh.
Một lưu ý quan trọng là các thành phần con đã đặt mergeDescendants
= true
sẽ không được đưa vào hoạt động hợp nhất. Hãy xem ví dụ sau:
![Mục danh sách có hình ảnh, một số văn bản và biểu tượng dấu trang](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-dagger.png?authuser=6&hl=vi)
Sau đây là một mục danh sách có thể nhấp vào. Khi người dùng nhấn vào hàng, ứng dụng sẽ chuyển đến trang chi tiết bài viết, nơi người dùng có thể đọc bài viết. Bên trong mục danh sách, có một nút để đánh dấu bài viết, biểu mẫu phần tử có thể nhấp vào được lồng, nên nút này sẽ xuất hiện riêng biệt trong cây đã hợp nhất. Nội dung còn lại trong hàng được hợp nhất:
![Cây hợp nhất chứa nhiều văn bản trong một danh sách bên trong nút Hàng. Cây chưa hợp nhất chứa các nút riêng cho mỗi thành phần kết hợp bằng Văn bản.](https://developer.android.google.cn/static/develop/ui/compose/images/semantics-merged-vs-unmerged.png?authuser=6&hl=vi)
Điều chỉnh cây Ngữ nghĩa
Như đã đề cập trước đó, bạn có thể ghi đè hoặc xoá một số thuộc tính ngữ nghĩa hoặc thay đổi hành vi hợp nhất của cây. Điều này đặc biệt phù hợp khi bạn đang tạo thành phần tuỳ chỉnh của riêng mình. Nếu không đặt giá trị chính xác thuộc tính và hành vi hợp nhất, ứng dụng của bạn có thể không truy cập được và các bài kiểm thử hành động khác với mong đợi của bạn. Để đọc thêm về một số trường hợp sử dụng phổ biến trong đó bạn nên điều chỉnh cây Ngữ nghĩa, hãy đọc bài viết Hỗ trợ tiếp cận . Nếu bạn muốn tìm hiểu thêm về kiểm thử, hãy xem phần kiểm thử hướng dẫn.
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
Đề 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
- Kiểm thử bố cục Compose