API 預設值

Material、Compose UI 和 Foundation API 預設會實作並提供許多無障礙功能設計做法。這些元素內含遵循特定角色和功能的內建語意。這表示大部分的無障礙支援功能都已提供,幾乎不需要額外作業。

為適當用途使用適當的 API,表示元件通常會提供預先定義的無障礙行為,涵蓋標準用途。不過,請務必再次確認這些預設值是否符合您的無障礙需求。如果沒有,Compose 也提供方法,可滿足更具體的需求。

瞭解 Compose API 中的預設無障礙語意和模式,有助於您使用這些 API 時兼顧無障礙功能。還能協助您在更多自訂元件中支援無障礙功能。

觸控目標大小下限

任何使用者可點擊、輕觸或進行互動的螢幕元素,都必須設為適當大小,方便使用者進行互動。設定這些元素的大小時,請務必將大小下限設為 48dp,以便正確遵循「Material Design 無障礙功能指南」。

「材質」元件,例如 CheckboxRadioButtonSwitchSliderSurface:請在內部設定此大小下限,但僅限元件可以接收使用者動作時。舉例來說,如果 CheckboxonCheckedChange 參數設為非空值,核取方塊就會包含至少 48 dp 的寬度和高度。

@Composable
private fun CheckableCheckbox() {
    Checkbox(checked = true, onCheckedChange = {})
}

核取方塊,寬度和高度為 48 dp,並採用預設邊框間距。
圖 1. 具有預設邊框間距的核取方塊。

onCheckedChange 參數設為空值時,系統不會納入邊框間距,因為該元件無法直接互動。

@Composable
private fun NonClickableCheckbox() {
    Checkbox(checked = true, onCheckedChange = null)
}

沒有邊框間距的核取方塊。
圖 2. 沒有邊框間距的核取方塊。

導入 SwitchRadioButtonCheckbox 等選取控制項時,您通常會將可點擊的行為推送至父項容器,方法是將可組合項的點擊回呼設為 null,然後在可組合父項中新增 toggleableselectable 輔助鍵。

@Composable
private fun CheckableRow() {
    MaterialTheme {
        var checked by remember { mutableStateOf(false) }
        Row(
            Modifier
                .toggleable(
                    value = checked,
                    role = Role.Checkbox,
                    onValueChange = { checked = !checked }
                )
                .padding(16.dp)
                .fillMaxWidth()
        ) {
            Text("Option", Modifier.weight(1f))
            Checkbox(checked = checked, onCheckedChange = null)
        }
    }
}

「選項」文字旁邊的核取方塊,可供選取和取消選取。
圖 3. 可點選的核取方塊。

如果可點擊的可組合項大小小於最低觸控目標大小,Compose 仍會增加觸控目標大小。方法是將觸控目標大小擴大到可組合項的範圍之外。

下列範例包含非常小的可點擊項 Box。觸控目標區域會自動擴大到 Box 的範圍以外,因此輕觸 Box 旁邊的按鈕仍會觸發點擊事件。

@Composable
private fun SmallBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .size(1.dp)
        )
    }
}

可點選的小方塊,輕觸方塊旁邊即可展開為較大的觸控目標。
圖 4. 可點擊的小方塊,展開後會變成較大的觸控目標。

為避免不同可組合項的觸控區域重疊,請務必針對大型可組合項使用夠大的最小尺寸。在範例中,這表示使用 sizeIn 修飾符設定內部方塊的最小大小:

@Composable
private fun LargeBox() {
    var clicked by remember { mutableStateOf(false) }
    Box(
        Modifier
            .size(100.dp)
            .background(if (clicked) Color.DarkGray else Color.LightGray)
    ) {
        Box(
            Modifier
                .align(Alignment.Center)
                .clickable { clicked = !clicked }
                .background(Color.Black)
                .sizeIn(minWidth = 48.dp, minHeight = 48.dp)
        )
    }
}

前一個範例中的小方塊會變大,以建立較大的觸控目標。
圖 5. 更大的方塊觸控目標。

圖像元素

定義 ImageIcon 可組合項時,Android 架構無法自動瞭解應用程式顯示的內容。您必須傳送圖像元素的文字說明。

請設想一個螢幕,可供使用者與好友分享目前的頁面。這個畫面包含可點擊的共用圖示:

可點選的四個圖示列,其中醒目顯示「分享」圖示。
圖 6. 可點選的圖示列,其中選取了「分享」圖示。

單憑藉圖示,Android 架構無從向視障使用者說明。Android 架構需要圖示的其他文字說明。

contentDescription 參數是用來描述圖像元素。請使用本地化字串,因為使用者會看到這個字串。

@Composable
private fun ShareButton(onClick: () -> Unit) {
    IconButton(onClick = onClick) {
        Icon(
            imageVector = Icons.Filled.Share,
            contentDescription = stringResource(R.string.label_share)
        )
    }
}

有些圖形元素只是單純裝飾用途,而您可能不想向使用者傳達這些元素。將 contentDescription 參數設為 null 時,您必須向 Android 架構表明這個元素沒有相關聯的動作或狀態。

@Composable
private fun PostImage(post: Post, modifier: Modifier = Modifier) {
    val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1)

    Image(
        painter = image,
        // Specify that this image has no semantic meaning
        contentDescription = null,
        modifier = modifier
            .size(40.dp, 40.dp)
            .clip(MaterialTheme.shapes.small)
    )
}

contentDescription 主要用於圖像元素,例如圖片。材質元件 (例如 ButtonText) 和可執行的行為 (例如 clickabletoggleable) 隨附其他預先定義的語意,可說明其內建行為,並透過其他 Compose API 變更。

互動式元素

Material 和 Foundation Compose API 會建立使用者可透過 clickabletoggleable 修飾符 API 互動的 UI 元素。由於可互動的元件可能由多個元素組成,clickabletoggleable 會預設合併子項的語意,將元件視為單一邏輯實體。

舉例來說,Material Button 可能包含子項圖示和一些文字。Material 會預設合併子項語意,而非將子項視為個別項目,因此無障礙服務可以據此將子項分組:Button

按鈕,其中包含未合併和已合併的子項語意。
圖 7. 按鈕,其中子項語意已合併和未合併。

同樣地,使用 clickable 修飾符也會導致可組合函式將子代的語意合併為單一實體,並傳送至無障礙服務,同時提供對應的動作表示法:

Row(
    // Uses `mergeDescendants = true` under the hood
    modifier = Modifier.clickable { openArticle() }
) {
    Icon(
        painter = painterResource(R.drawable.ic_logo),
        contentDescription = "Open",
    )
    Text("Accessibility in Compose")
}

您也可以在父項可點選項目上設定特定 onClickLabel,向無障礙服務提供額外資訊,並更精確地呈現動作:

Row(
    modifier = Modifier
        .clickable(onClickLabel = "Open this article") {
            openArticle()
        }
) {
    Icon(
        painter = painterResource(R.drawable.ic_logo),
        contentDescription = "Open"
    )
    Text("Accessibility in Compose")
}

以 TalkBack 為例,這個 clickable 修飾符和其點擊標籤會讓 TalkBack 提供「輕觸兩下即可開啟這篇文章」的動作提示,而不是「輕觸兩下即可啟用」這類較為通用的預設回饋。

這項意見回饋會因動作類型而異。長按時,TalkBack 會提示「輕觸兩下並按住可」,後面接著標籤:

Row(
    modifier = Modifier
        .combinedClickable(
            onLongClickLabel = "Bookmark this article",
            onLongClick = { addToBookmarks() },
            onClickLabel = "Open this article",
            onClick = { openArticle() },
        )
) {}

在某些情況下,您可能無法直接存取 clickable 修飾符 (例如,修飾符是在較低的巢狀層中設定),但仍想變更預設的公告標籤。如要這麼做,請使用 semantics 修飾符,將設定 clickable 與修改公告分開,並在該處設定點擊標籤,以修改動作表示法:

@Composable
private fun ArticleList(openArticle: () -> Unit) {
    NestedArticleListItem(
        // Clickable is set separately, in a nested layer:
        onClickAction = openArticle,
        // Semantics are set here:
        modifier = Modifier.semantics {
            onClick(
                label = "Open this article",
                action = {
                    // Not needed here: openArticle()
                    true
                }
            )
        }
    )
}

您不需要傳遞兩次點擊動作。現有的 Compose API (例如 clickableButton) 會為您處理這項作業。合併邏輯會驗證最外層的修飾符標籤和動作是否適用於現有資訊。在上述範例中,NestedArticleListItem 會自動將 openArticle() 點選動作傳遞至其 clickable 語意。您可以在第二個語意修飾詞動作中,將點擊動作留空。不過,由於第一個語意修飾符中沒有點擊標籤,因此系統會從第二個語意修飾符 onClick(label = "Open this document") 中擷取。

您可能會遇到預期子項語意會合併到父項語意中,但實際並未發生的情況。如需更多資訊,請參閱「合併及清除」一文。

自訂元件

建構自訂元件時,請查看 Material 程式庫或其他 Compose 程式庫中類似元件的實作項目。然後視需要模擬或修改其無障礙功能行為。舉例來說,如果您將 Material Checkbox 替換成自己的實作項目,查看現有的 Checkbox 實作項目時,會提醒您加入 triStateToggleable 修飾符,負責處理元件的無障礙屬性。此外,請多多利用 Foundation 修飾符,因為前者內建便有考慮無障礙功能,且包含本節涵蓋的現有 Compose 做法。

您也可以在「清除及設定語意區段」中找到自訂切換按鈕元件的範例,並在 API 指南中找到如何支援自訂元件無障礙功能的詳細資訊。