提升應用程式無障礙程度的基本原則

為了滿足使用者的無障礙需求,Android 架構可讓您建立無障礙服務,以便對使用者呈現應用程式內容,並代為操作應用程式。

Android 提供多種系統無障礙服務,包括以下項目:

  • TalkBack:輔助低視能或失明的使用者。透過合成語音朗讀內容,並根據使用者手勢在應用程式中執行對應動作。
  • 切換控制功能:輔助動作失能的使用者。醒目顯示互動性元素,並在使用者按下按鈕時執行對應動作,讓使用者只透過一或兩個按鈕就能控制裝置。

為了協助具有無障礙需求的使用者順利使用應用程式,應用程式必須採用本頁所述的最佳做法。這些最佳做法是以「提高應用程式的無障礙程度」一文所述的準則為基礎。

這些最佳做法可進一步提高應用程式的無障礙程度,如以下各節說明:

標籤元素
針對應用程式中每個有意義的互動性 UI 元素,使用者必須能夠瞭解其內容和用途。
新增無障礙功能動作
加入無障礙動作選項,可讓無障礙服務的使用者在應用程式中完成重要的使用者流程。
使用內建無障礙功能
Compose 預設提供許多無障礙功能行為。善用預先定義的無障礙行為,讓元件無障礙功能運作,不必額外處理或只需少量處理。Compose 也提供方法,支援預設功能未涵蓋的更具體無障礙需求。
使用顏色以外的提示
使用者必須能清楚區分 UI 中不同類別的元素。因此,使用顏色區別元素時,也請使用圖案、位置來呈現差異。
提高媒體內容的無障礙程度
為應用程式的影片或音訊內容加入說明,讓存取這些內容的使用者不必完全仰賴視覺或聽覺提示。

標籤元素

針對應用程式中的每個互動式 UI 元素,請務必為使用者提供實用的描述性標籤。每個標籤都必須說明特定元素的元件資訊,也就是元素的含義和用途。TalkBack 等螢幕閱讀器可為使用者朗讀這些標籤。

在大多數情況下,Compose API 和 Material 都已預設支援無障礙功能。不過,如要手動指定 UI 元素的語意屬性,請使用 semantics 修飾符和 contentDescription 屬性。如要進一步瞭解語意,請參閱「語意」。

以下各節將說明其他幾種標籤的使用技巧。

可編輯元素

為可編輯元素 (例如文字欄位) 加上標籤時,您可以在元素本身中提供有效輸入的範例,除了讓螢幕閱讀器讀取這個範例文字,顯示該文字也會很有幫助。在這種情況下,您可以使用預留位置文字,也稱為提示文字。

在以下範例中,TextField 具有提供提示文字的 placeholder 參數。

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

文字欄位通常也會有對應的說明標籤,用於說明使用者必須輸入的內容。

在以下範例中,TextField 具有提供無障礙說明的 label 參數。

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

如要進一步瞭解文字和使用者輸入內容,請參閱「設定文字欄位」。

集合中的元素

為集合中的元素加上標籤時,所有標籤都不得重複。這樣一來,系統的無障礙服務在朗讀標籤時,才能僅參照一個螢幕上的元素。這種關聯可讓使用者知道自己已循環瀏覽 UI,或是已將焦點移到先前瀏覽過的元素。

舉例來說,如果您有 LazyColumnLazyRow,請使用 semantics 修飾符為每個項目指派不重複的 collectionItemInfo,如下列程式碼片段所示:

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)
            }
        )
    }
}

如要進一步瞭解清單和格線的語意屬性,請參閱「清單和項目資訊」。

相關內容群組

如果應用程式會顯示多個 UI 元素,且這些元素會形成自然群組 (例如歌曲詳細資料或訊息屬性),請將這些元素設置在父項容器內 (例如 ColumnRowBox)。使用父項容器的 semantics 修飾符,將 mergeDescendants 設為 true

這樣一來,無障礙服務就能在單次朗讀中逐一提供內部元素的內容說明。整合相關元素後,輔助技術的使用者就能更有效率地探索螢幕上的資訊。

在下列程式碼片段中,Row 可組合函式會做為父項容器。Row 內有相關元素,可顯示網誌文章的中繼資料,包括作者的個人資料相片、作者姓名和預估閱讀時間。將 mergeDescendants 設為 true 會將這些內部元素分組,因此無障礙服務可以將這些元素視為一個單位。

@Composable
private fun PostMetadata(metadata: Metadata) {
    // Merge elements below for accessibility purposes
    Row(modifier = Modifier.semantics(mergeDescendants = true) {}) {
        Image(
            imageVector = Icons.Filled.AccountCircle,
            contentDescription = null // decorative
        )
        Column {
            Text(metadata.author.name)
            Text("${metadata.date}${metadata.readTimeMinutes} min read")
        }
    }
}

如上例所示,分組相關元素時,請只讓父項容器具有互動性。避免在內部子項元素中加入 clickablefocusable 修飾符。請改為將修飾符套用至父項 RowColumn

由於無障礙服務會一次讀完內部元素的說明,因此每則說明務必盡量保持精簡,同時清楚傳達元素的含義。

注意:一般來說,建立群組內容說明時,應避免單純匯總子項文字。如果這麼做,群組說明會顯得生硬,而且當子項文字有所變更時,群組說明可能會與顯示的文字不相符。

在清單或格線情境下,螢幕閱讀器可能會合併清單或格線元素的子項文字節點。建議您避免修改此朗讀內容。

如要進一步瞭解合併語意,請參閱「合併及清除」。

文字中的標題

部分應用程式會使用「標題」統整螢幕上顯示的文字群組。如果特定元素代表標題,您可以將 semantics 修飾符中的 heading 屬性設為 ,為無障礙服務指出其用途。

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

無障礙服務的使用者可以選擇依標題 (而不是依段落或字詞) 瀏覽,透過這項彈性享有更優異的文字瀏覽體驗。

如要進一步瞭解 heading 語意屬性,請參閱「標題」。

無障礙窗格標題

在 Android 9 (API 級別 28) 以上版本中,您可以為螢幕的「窗格」提供能夠滿足無障礙需求的標題。就無障礙功能來說,窗格是視窗中看起來與眾不同的部分。

為了讓無障礙服務瞭解窗格的類視窗行為,請為應用程式的窗格提供描述性的標題。當窗格的外觀或內容有所改變時,無障礙服務就能為使用者提供更精細的資訊。

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

如要進一步瞭解 paneTitle 語意屬性,請參閱「類似視窗的元件」。

裝飾性元素

如果 UI 中的元素只是用於保持視覺間隔或外觀,請在該元素上設定適當的屬性,指出無障礙服務可以忽略該元素。

如果是 ImageIcon 可組合函式,請設定 contentDescription = null。如果是其他純裝飾性元素,不提供任何內容或功能,則可以使用 hideFromAccessibility。這項語意屬性會告知無障礙服務忽略該項目。

如果互動式可組合函式包含裝飾性非互動式子項元素,請使用 clearAndSetSemantics,確保無障礙服務不會遍歷這些元素。請注意,clearAndSetSemantics 會完全清除元素及其子項的預設語意。這樣您就能定義新的統一無障礙元素。通常,您會對複雜的自訂元件使用這個方法。

在下列範例中,IconText 是自訂切換開關內的裝飾子項元素。如要避免無障礙服務個別遍歷這些子項,您可以在父項 Row 上使用 clearAndSetSemantics 清除子項的語意。這會告知無障礙服務將整個 Row 視為可遍歷的切換按鈕:

// Developer might intend this to be a toggleable.
// Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied,
// a custom description is set, and a Role is applied.

@Composable
fun FavoriteToggle() {
    val checked = remember { mutableStateOf(true) }
    Row(
        modifier = Modifier
            .toggleable(
                value = checked.value,
                onValueChange = { checked.value = it }
            )
            .clearAndSetSemantics {
                stateDescription = if (checked.value) "Favorited" else "Not favorited"
                toggleableState = ToggleableState(checked.value)
                role = Role.Switch
            },
    ) {
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null // not needed here

        )
        Text("Favorite?")
    }
}

如要進一步瞭解如何清除語意,請參閱「清除及設定語意」。

新增無障礙功能操作

請務必確保無障礙服務使用者能完成應用程式中的所有使用者流程。

如果自訂可組合函式的互動會以不明顯的方式變更應用程式的狀態,請使用 Modifier.clickableModifier.combinedClickable 中的 onClickLabelonLongClickLabel 等參數,為標準輕觸動作提供描述性標籤。

如要處理無法對應至標準輕觸的複雜互動,請使用 customActions

舉例來說,如果應用程式允許使用者將項目拖曳至其他位置,或滑動清單中的項目,您可以向無障礙服務公開這項動作,提供完成這些使用者流程的替代方式。這樣一來,TalkBack、Voice Access 或切換控制功能的使用者就能執行原本只能透過手勢進行的操作。

在 Compose 中,您可以使用 semantics 修飾符中的 customActions 屬性,透過 CustomAccessibilityAction 定義自訂無障礙動作。

舉例來說,如果您的應用程式允許使用者滑動項目來關閉,您可以透過自訂無障礙動作來公開這項功能:

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()
}

實作自訂無障礙功能動作後,使用者可以透過動作選單存取動作。

如要進一步瞭解自訂動作,請參閱「自訂動作」。

讓可使用的操作容易理解

如果 UI 元素支援按住等動作,TalkBack 這類無障礙服務就會朗讀「輕觸兩下並長按」。

這則通用朗讀內容並未提供任何背景資訊,讓使用者瞭解按住動作的作用。

如要讓這項公告更有用,請為動作指定有意義的說明。

在 Compose 中,標準互動修飾符 (例如 clickablecombinedClickable) 內建參數 (即 onClickLabelonLongClickLabel),可用於提供動作說明,如下例所示:

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

這可讓 TalkBack 朗讀「開啟內容選單」,協助使用者瞭解這個動作的用途。

您也可以直接在 semantics 修飾符中指定標籤。

如要進一步瞭解如何回應輕觸和點擊動作,請參閱「輕觸和按壓」和「互動式元素」。

使用內建無障礙功能

設計應用程式的 UI 時,請善用內建的無障礙功能,避免重新實作現有的功能。Material、Compose UI 和 Foundation API 預設會實作並提供許多無障礙功能做法。

在 Jetpack Compose 中,使用 ButtonSwitchCheckbox 等內建可組合函式,建立無障礙 UI。這些元件已預先封裝 semantics 修飾符 (例如 rolestateDescription),可用於提升應用程式的無障礙程度。

將語意套用至自訂元件

建立自訂元件時,請注意這個元件需要哪些無障礙支援,才能發揮作用。通常您已使用的標準 Compose API (例如 clickabletoggleableselectable) 就已足夠,因為這些 API 會自動填入語意樹狀結構。

不過,部分元件需要比標準修飾符提供的資訊更具體。在這些情況下,請尋找專用修飾符 (例如 triStateToggleable),如果沒有,請使用低階 Modifier.semantics 明確提供語意。

舉例來說,假設有一個 TriStateSwitch,這是一個具有三種狀態 (開啟、關閉和不確定) 的切換開關。

標準 toggleable 修飾符會假設有兩種狀態,但 triStateToggleable 修飾符會處理第三種狀態的複雜性。系統會自動設定無障礙 Role (Switch) 和 State。這樣一來,無障礙服務就能收到正確資訊,您也不必手動定義語意。

下列程式碼片段顯示使用這種方法的 TriStateSwitch

@Composable
fun TriStateSwitch(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    // A real implementation would include custom drawing for the switch.
    // This example uses a Box to demonstrate the semantics.
    Box(
        modifier = modifier
            .size(width = 64.dp, height = 40.dp)
            // triStateToggleable handles the semantics (Role and State)
            // automatically, so explicit Modifier.semantics is not needed here.
            .triStateToggleable(
                state = state,
                onClick = onClick,
                role = Role.Switch
            )
            // Add visual feedback based on the state
            .background(
                when (state) {
                    ToggleableState.On -> Color.Green
                    ToggleableState.Off -> Color.Gray
                    ToggleableState.Indeterminate -> Color.Yellow
                }
            )
    )
}

// Usage within another composable:
var state by remember { mutableStateOf(ToggleableState.Off) }
TriStateSwitch(
    state = state,
    onClick = {
        state = when (state) {
            ToggleableState.Off -> ToggleableState.Indeterminate
            ToggleableState.Indeterminate -> ToggleableState.On
            ToggleableState.On -> ToggleableState.Off
        }
    }
)

建構自訂元件時,請務必提供所有相關語意屬性,以利無障礙功能運作。舉例來說,如果您的元件模仿標準控制項 (例如切換鈕或按鈕),這些屬性會包含元件的角色 (例如 Role.SwitchRole.Button)、stateDescription (例如「開啟」、「關閉」、「已勾選」或「未勾選」),以及任何相關動作標籤。詳情請參閱「自訂元件」。

使用顏色以外的提示

為了輔助色盲使用者,請使用顏色以外的提示來區分應用程式畫面中的 UI 元素,包括運用不同的形狀或大小、提供文字或視覺圖像,或是加入語音或觸控 (觸動) 回饋來呈現不同元素的差異。

圖 1 顯示同一活動的兩個版本。其中一個版本只使用顏色來區分工作流程中的兩個可能動作。另一個版本則採用最佳做法,除了顏色以外還利用形狀和文字來凸顯兩個選項的差異:

左側是螢幕,上面有兩個圓形按鈕,分別是綠色和紅色。右側是相同的畫面,但兩個圓形按鈕標示了文字和有意義的圖示。
圖 1:僅使用顏色建立 UI 元素的範例 (左),以及使用顏色、形狀和文字建立 UI 元素的範例 (右)

提高媒體內容的無障礙程度

如果您開發的應用程式包含媒體內容 (例如短片或音訊錄音),請設法為具有不同類型無障礙需求的使用者提供支援,協助他們理解這些內容。請特別嘗試下列動作:

  • 加入控制項,讓使用者暫停或停止播放媒體、變更音量及切換字幕。
  • 如果影片中的資訊是完成工作流程的關鍵,請以轉錄稿等替代格式提供相同內容。

其他資源

如要進一步瞭解如何提高應用程式的無障礙程度,請參閱下列其他資源:

程式碼研究室

Views content