Ngữ nghĩa

Ngoài thông tin chính mà một thành phần kết hợp mang theo, chẳng hạn như chuỗi văn bản của thành phần kết hợp Text, bạn có thể cần thêm thông tin bổ sung về các thành phần trên giao diện người dùng.

Thông tin về ý nghĩa và vai trò của một thành phần trong Compose được gọi là ngữ nghĩa. Đây là một cách để cung cấp thêm ngữ cảnh về các thành phần kết hợp cho các dịch vụ như hỗ trợ tiếp cận, tự động điền và kiểm thử. Ví dụ: biểu tượng máy ảnh có thể chỉ là một hình ảnh, nhưng ý nghĩa ngữ nghĩa có thể là "Chụp ảnh".

Bằng cách kết hợp ngữ nghĩa thích hợp với các API Compose thích hợp, bạn sẽ cung cấp nhiều thông tin nhất có thể về thành phần của mình cho các dịch vụ hỗ trợ tiếp cận. Sau đó, các dịch vụ này sẽ quyết định cách trình bày thành phần đó cho người dùng.

Material và Compose UI và Foundation API có ngữ nghĩa tích hợp theo vai trò và chức năng cụ thể của chúng, nhưng bạn cũng có thể sửa đổi các ngữ nghĩa này cho các API hiện có hoặc đặt các ngữ nghĩa mới cho các thành phần tuỳ chỉnh, theo yêu cầu cụ thể của bạn.

Thuộc tính ngữ nghĩa

Thuộc tính ngữ nghĩa truyền tải ý nghĩa của thành phần kết hợp tương ứng. Ví dụ: thành phần kết hợp Text chứa 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 do nhà phát triển đặt) truyền tải văn bản về ý nghĩa của biểu tượng.

Hãy xem xét 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 một Switch. Đây là giao diện mà người dùng thấy:

Hình 1. Switch ở trạng thái "Bật" và "Tắt".

Để mô tả ý nghĩa của phần tử này, bạn có thể nói như sau: "Đây là Nút chuyển, là một phần tử có thể chuyển đổi ở trạng thái "Bật". Bạn có thể nhấp vào phần này để tương tác với phần này."

Đâ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 hiển thị với Layout Inspector:

Layout Inspector hiển thị các thuộc tính ngữ nghĩa của một thành phần kết hợp Nút chuyển
Hình 2. Layout Inspector hiển thị các thuộc tính ngữ nghĩa của một thành phần kết hợp Switch.

Role cho biết loại phần tử. StateDescription mô tả cách tham chiếu trạng thái "Bật". Theo mặc định, đây là phiên bản đã bản địa hoá của từ "Bật". Tuy nhiên, phiên bản này có thể được đặt cụ thể hơn (ví dụ: "Đã bật") dựa trên ngữ cảnh. ToggleableState là trạng thái hiện tại của Nút chuyể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.

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ẽ:

  • Các dịch vụ hỗ trợ tiếp cận sử dụng các thuộc tính để biểu thị giao diện người dùng hiển thị trên màn hình và cho phép người dùng tương tác với giao diện đó. Đối với thành phần kết hợp Nút chuyển, Talkback có thể thông báo: "Đang bật; Nút chuyển; nhấn đúp để chuyển". Người dùng có thể nhấn đúp vào màn hình để 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:
    val mySwitch = SemanticsMatcher.expectValue(
        SemanticsProperties.Role, Role.Switch
    )
    composeTestRule.onNode(mySwitch)
        .performClick()
        .assertIsOff()

Theo mặc định, các thành phần kết hợp và đối tượng sửa đổi được tạo dựa trên thư viện nền tảng Compose đã đặt các thuộc tính có liên quan cho bạn. Bạn có thể thay đổi các thuộc tính này theo cách thủ công để cải thiện tính năng hỗ trợ tiếp cận cho các trường hợp sử dụng cụ thể hoặc thay đổi chiến lược hợp nhất hoặc xoá của thành phần kết hợp.

Để báo hiệu loại nội dung cụ thể của thành phần cho các dịch vụ hỗ trợ tiếp cận, bạn có thể áp dụng nhiều ngữ nghĩa khác nhau. Những nội dung bổ sung này sẽ hỗ trợ thông tin ngữ nghĩa chính và giúp các dịch vụ hỗ trợ tiếp cận tinh chỉnh cách thành phần của bạn được trình bày, thông báo hoặc tương tác.

Để biết danh sách đầy đủ các thuộc tính ngữ nghĩa, hãy xem đối tượng SemanticsProperties. Để biết danh sách đầy đủ các Hành động hỗ trợ tiếp cận có thể thực hiện, hãy xem đối tượng SemanticsActions.

Tiêu đề

Ứng dụng thường chứa các màn hình có nội dung giàu văn bản, chẳng hạn như các bài viết dài hoặc trang tin tức, thường được chia thành nhiều tiểu mục có tiêu đề:

Một bài đăng trên blog có nội dung bài viết trong một vùng chứa có thể cuộn.
Hình 3. Một bài đăng trên blog có nội dung bài viết trong một vùng chứa có thể cuộn.

Người dùng có nhu cầu hỗ trợ tiếp cận có thể gặp khó khăn khi điều hướng trên một màn hình như vậy. Để cải thiện trải nghiệm điều hướng, một số dịch vụ hỗ trợ tiếp cận cho phép điều hướng trực tiếp dễ dàng hơn giữa các phần hoặc tiêu đề. Để bật tính năng này, hãy cho biết thành phần của bạn là heading bằng cách xác định thuộc tính ngữ nghĩa của thành phần đó:

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

Cảnh báo và cửa sổ bật lên

Nếu thành phần của bạn là một cảnh báo hoặc cửa sổ bật lên, chẳng hạn như Snackbar, bạn nên báo hiệu cho các dịch vụ hỗ trợ tiếp cận rằng có thể truyền tải cấu trúc mới hoặc nội dung cập nhật cho người dùng.

Bạn có thể đánh dấu các thành phần giống cảnh báo bằng thuộc tính ngữ nghĩa liveRegion. Điều này cho phép các dịch vụ hỗ trợ tiếp cận tự động thông báo cho người dùng về các thay đổi đối với thành phần này hoặc các thành phần con của thành phần này:

PopupAlert(
    message = "You have a new message",
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Polite
    }
)

Bạn nên sử dụng liveRegionMode.Polite trong hầu hết các trường hợp mà sự chú ý của người dùng chỉ cần được thu hút ngắn gọn đến các cảnh báo hoặc nội dung thay đổi quan trọng trên màn hình.

Bạn nên hạn chế sử dụng liveRegion.Assertive để tránh phản hồi gây gián đoạn. Bạn nên sử dụng tính năng này trong những trường hợp cần thiết để người dùng biết về nội dung có giới hạn thời gian:

PopupAlert(
    message = "Emergency alert incoming",
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Assertive
    }
)

Bạn không nên sử dụng vùng trực tiếp trên nội dung cập nhật thường xuyên, chẳng hạn như đồng hồ đếm ngược, để tránh làm người dùng choáng ngợp với phản hồi liên tục.

Thành phần giống cửa sổ

Các thành phần tuỳ chỉnh giống cửa sổ, tương tự như ModalBottomSheet, cần có thêm các tín hiệu để phân biệt với nội dung xung quanh. Để làm việc này, bạn có thể sử dụng ngữ nghĩa paneTitle để mọi thay đổi liên quan đến cửa sổ hoặc ngăn đều có thể được dịch vụ hỗ trợ tiếp cận thể hiện một cách thích hợp, cùng với thông tin ngữ nghĩa chính của cửa sổ hoặc ngăn đó:

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

Để tham khảo, hãy xem cách Material 3 sử dụng paneTitle cho các thành phần của nó.

Thành phần lỗi

Đối với các loại nội dung khác, chẳng hạn như các thành phần giống lỗi, bạn nên mở rộng thông tin ngữ nghĩa chính cho những người dùng có nhu cầu hỗ trợ tiếp cận. Khi xác định trạng thái lỗi, bạn có thể thông báo cho các dịch vụ hỗ trợ tiếp cận về ngữ nghĩa error và cung cấp thông báo lỗi mở rộng.

Trong ví dụ này, TalkBack đọc thông tin văn bản lỗi chính, theo sau là thông báo mở rộng bổ sung:

Error(
    errorText = "Fields cannot be empty",
    modifier = Modifier
        .semantics {
            error("Please add both email and password")
        }
)

Thành phần theo dõi tiến trình

Đối với các thành phần tuỳ chỉnh theo dõi tiến trình, bạn nên thông báo cho người dùng về các thay đổi về tiến trình, bao gồm cả giá trị tiến trình hiện tại, phạm vi và kích thước bước. Bạn có thể thực hiện việc này bằng ngữ nghĩa progressBarRangeInfo. Điều này đảm bảo rằng các dịch vụ hỗ trợ tiếp cận nhận biết được các thay đổi về tiến trình và có thể cập nhật người dùng cho phù hợp. Các công nghệ hỗ trợ khác nhau cũng có thể có cách riêng để gợi ý về việc tăng và giảm tiến trình.

ProgressInfoBar(
    modifier = Modifier
        .semantics {
            progressBarRangeInfo =
                ProgressBarRangeInfo(
                    current = progress,
                    range = 0F..1F
                )
        }
)

Thông tin về danh sách và mục

Trong danh sách và lưới tuỳ chỉnh có nhiều mục, các dịch vụ hỗ trợ tiếp cận cũng có thể nhận được thông tin chi tiết hơn, chẳng hạn như tổng số mục và chỉ mục.

Bằng cách sử dụng ngữ nghĩa collectionInfocollectionItemInfo tương ứng trên danh sách và các mục, trong danh sách dài này, các dịch vụ hỗ trợ tiếp cận có thể thông báo cho người dùng về chỉ mục mục họ đang ở trong tổng số bộ sưu tập, ngoài thông tin ngữ nghĩa dạng văn bản:

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

Mô tả trạng thái

Thành phần kết hợp có thể xác định stateDescription cho ngữ nghĩa mà khung Android sử dụng để đọc trạng thái của thành phần kết hợp đó. Ví dụ: một thành phần có thể kết hợp có thể chuyển đổi có thể ở trạng thái "đã đánh dấu" hoặc "bỏ đánh dấu". Trong một số trường hợp, bạn nên ghi đè các nhãn mô tả trạng thái mặc định mà Compose sử dụng. Bạn có thể làm việc này bằng cách chỉ định rõ ràng nhãn mô tả trạng thái trước khi xác định một thành phần có thể kết hợp có thể chuyển đổi:

@Composable
private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) {
    val stateSubscribed = stringResource(R.string.subscribed)
    val stateNotSubscribed = stringResource(R.string.not_subscribed)
    Row(
        modifier = Modifier
            .semantics {
                // Set any explicit semantic properties
                stateDescription = if (selected) stateSubscribed else stateNotSubscribed
            }
            .toggleable(
                value = selected,
                onValueChange = { onToggle() }
            )
    ) {
        /* ... */
    }
}

Thao tác tuỳ chỉnh

Bạn có thể sử dụng Thao tác tuỳ chỉnh cho các cử chỉ trên màn hình cảm ứng phức tạp hơn, chẳng hạn như vuốt để đóng hoặc kéo và thả, vì những cử chỉ này có thể gây khó khăn cho người dùng bị suy giảm chức năng vận động hoặc các khuyết tật khác khi tương tác.

Để giúp cử chỉ vuốt để đóng dễ tiếp cận hơn, bạn có thể liên kết cử chỉ này với một thao tác tuỳ chỉnh, chuyển thao tác đóng và nhãn ở đó:

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

Sau đó, một dịch vụ hỗ trợ tiếp cận như TalkBack sẽ làm nổi bật thành phần và gợi ý rằng có nhiều thao tác khác trong trình đơn của thành phần đó, đại diện cho thao tác vuốt để đóng ở đó:

Hình ảnh trình đơn thao tác của TalkBack
Hình 4. Hình ảnh trình đơn thao tác của TalkBack.

Một trường hợp sử dụng khác của thao tác tuỳ chỉnh là danh sách dài có các mục có nhiều thao tác hơn, vì người dùng có thể sẽ thấy phiền khi phải lặp lại từng thao tác cho từng mục:

=Hình ảnh minh hoạ cách điều hướng bằng tính năng Tiếp cận bằng công tắc trên màn hình
Hình 5. Hình ảnh minh hoạ cách điều hướng bằng tính năng Tiếp cận bằng công tắc trên màn hình.

Để cải thiện trải nghiệm điều hướng (đặc biệt hữu ích cho các công nghệ hỗ trợ dựa trên tương tác như Tiếp cận bằng công tắc hoặc Điều khiển bằng giọng nói), bạn có thể sử dụng các thao tác tuỳ chỉnh trên vùng chứa để di chuyển các thao tác ra khỏi thao tác di chuyển riêng lẻ và vào một trình đơn thao tác riêng:

ArticleListItemRow(
    modifier = Modifier
        .semantics {
            customActions = listOf(
                CustomAccessibilityAction(
                    label = "Open article",
                    action = {
                        openArticle()
                        true
                    }
                ),
                CustomAccessibilityAction(
                    label = "Add to bookmarks",
                    action = {
                        addToBookmarks()
                        true
                    }
                ),
            )
        }
) {
    Article(
        modifier = Modifier.clearAndSetSemantics { },
        onClick = openArticle,
    )
    BookmarkButton(
        modifier = Modifier.clearAndSetSemantics { },
        onClick = addToBookmarks,
    )
}

Trong những trường hợp này, hãy nhớ xoá ngữ nghĩa của phần tử con ban đầu bằng đối tượng sửa đổi clearAndSetSemantics theo cách thủ công, vì bạn đang di chuyển các phần tử con đó vào hành động tuỳ chỉnh.

Lấy ví dụ về tính năng Tiếp cận bằng công tắc, trình đơn của tính năng này sẽ mở ra khi bạn chọn vùng chứa và liệt kê các thao tác lồng nhau có sẵn tại đó:

Tính năng Tiếp cận bằng công tắc làm nổi bật mục danh sách bài viết
Hình 6. Tính năng Tiếp cận bằng công tắc làm nổi bật mục danh sách bài viết.
Hình ảnh trình đơn thao tác của tính năng Tiếp cận bằng công tắc.
Hình 7. Hình ảnh trình đơn thao tác của tính năng Tiếp cận bằng công tắc.

Cây ngữ nghĩa

Thành phần Compose 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 các thành phần kết hợp. Cấu trúc là một cấu trúc dạng cây bao gồm các thành phần kết hợp mô tả giao diện người dùng của bạn.

Bên cạnh Bản soạn, có một cây song, có tên là cây ngữ nghĩa. Cây này mô tả giao diện người dùng của bạn theo cách dễ hiểu đối với các dịch vụ Hỗ trợ tiếp cận và cho khung Kiểm thử. Các dịch vụ hỗ trợ tiếp cận sử dụng cây để mô tả ứng dụng cho người dùng có nhu cầu cụ thể. Khung kiểm thử sử dụng cây này để tương tác với ứng dụng của bạn và đưa ra xác nhận về ứng dụng đó. 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
Hình 8. Một hệ phân cấp giao diện người dùng điển hình và cây ngữ nghĩa.

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 các thành phần kết hợp cấp thấp tuỳ chỉnh, 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 tương ứng với các phần tử ngày có thể chọn
Hình 9. Một thành phần kết hợp lịch tuỳ chỉnh tương ứng với các phần tử ngày có thể chọn.

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 được đủ 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 thì sẽ đọc "Lịch tháng tư", và người dùng sẽ vẫn thắc mắc về ngày đã chọn. Để giúp thành phần kết hợp này dễ dàng tiếp cận hơn, bạn cần thêm thông tin ngữ nghĩa theo cách thủ công.

Cây đã 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 không đặt thuộc tính ngữ nghĩa, thì tệp đó 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 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 như vậy là Button. Bạn có thể xem nút là một phần tử duy nhất, mặc dù nút đó 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 trình bày dưới dạng một nút lá đơn trong cây:

Biểu diễn ngữ nghĩa lá đơn hợp nhất
Hình 10. Biểu diễn ngữ nghĩa lá đơn hợp nhất.

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ụ Button, thành phần kết hợp Button sử dụng đối tượng sửa đổi clickable nội bộ bao gồm đối tượng sửa đổi semantics này. Do đó, các nút con của nút sẽ được hợp nhất. Hãy đọc tài liệu về tính 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 của mình.

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 clickabletoggleable 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ây ngữ nghĩa thực sự là hai cây khác nhau. Có một cây Ngữ nghĩa hợp nhất, hợp nhất các nút con khi mergeDescendants được đặt thành true. Ngoài ra, còn có một cây Ngữ nghĩa chưa được hợp nhất không áp dụng tính năng hợp nhất mà giữ nguyên mọi nút. Các dịch vụ hỗ trợ tiếp cận sử dụng cây chưa hợp nhất và áp dụng các thuật toán hợp nhất của riêng mình, có tính đến thuộc tính mergeDescendants. 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, như trong các ví dụ trước đó, cây đã hợp nhất sẽ được ghi lại. Để in cây chưa được hợp nhất, 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ả cây ngữ nghĩa hợp nhất và chưa hợp nhất, bằng cách chọn một cây ưa thích trong bộ lọc khung hiển thị:

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
Hình 11. 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.

Đố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:

Các thuộc tính ngữ nghĩa được hợp nhất và đặt
Hình 12. Các thuộc tính ngữ nghĩa được hợp nhất và đặt.

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. Do đó, bạn có thể tương tác với Button bằng cách so khớp văn bản hiển thị bên trong nút đó:

composeTestRule.onNodeWithText("Like").performClick()

Ghi đè hành vi này bằng cách đặt tham số useUnmergedTree của trình so khớp thành true, như với trình so khớp onRoot.

Điều chỉnh cây

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 các thành phần tuỳ chỉnh của riêng mình. Nếu không đặt đúng 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 lần kiểm thử có thể hoạt động khác với dự kiến. Nếu bạn muốn tìm hiểu thêm về kiểm thử, hãy xem hướng dẫn kiểm thử.