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

為了滿足使用者的無障礙需求,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,或是已將焦點移到先前瀏覽過的元素。

舉例來說,如果您有 LazyColumn 或 LazyRow,請使用 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 元素,且這些元素會形成自然群組 (例如歌曲詳細資料或訊息屬性),請將這些元素設置在父項容器內 (例如 Column、Row 或 Box)。使用父項容器的 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")
        }
    }
}

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

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

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

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

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

文字中的標題

部分應用程式會使用「標題」統整螢幕上顯示的文字群組。如果特定元素代表標題,您可以將 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 中的元素只是用於保持視覺間隔或外觀,請在該元素上設定適當的屬性,指出無障礙服務可以忽略該元素。

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

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

在下列範例中,Icon 和 Text 是自訂切換開關內的裝飾子項元素。如要避免無障礙服務個別遍歷這些子項,您可以在父項 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.clickable 或 Modifier.combinedClickable 中的 onClickLabel 或 onLongClickLabel 等參數,為標準輕觸動作提供描述性標籤。

如要處理無法對應至標準輕觸的複雜互動,請使用 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 中,標準互動修飾符 (例如 clickable 和 combinedClickable) 內建參數 (即 onClickLabel 和 onLongClickLabel),可用於提供動作說明,如下例所示:

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 中,使用 Button、Switch 和 Checkbox 等內建可組合函式,建立無障礙 UI。這些元件已預先封裝 semantics 修飾符 (例如 role 和 stateDescription),可用於提升應用程式的無障礙程度。

將語意套用至自訂元件

建立自訂元件時,請注意這個元件需要哪些無障礙支援,才能發揮作用。通常您已使用的標準 Compose API (例如 clickable、toggleable 或 selectable) 就已足夠,因為這些 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.Switch 或 Role.Button)、stateDescription (例如「開啟」、「關閉」、「已勾選」或「未勾選」),以及任何相關動作標籤。詳情請參閱「自訂元件」。

使用顏色以外的提示

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

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

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

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

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

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

其他資源

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

程式碼研究室

Views content