為了滿足使用者的無障礙需求,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 顯示同一活動的兩個版本。其中一個版本只使用顏色來區分工作流程中的兩個可能動作。另一個版本則採用最佳做法,除了顏色以外還利用形狀和文字來凸顯兩個選項的差異:
提高媒體內容的無障礙程度
如果您開發的應用程式包含媒體內容 (例如短片或音訊錄音),請設法為具有不同類型無障礙需求的使用者提供支援,協助他們理解這些內容。請特別嘗試下列動作:
- 加入控制項,讓使用者暫停或停止播放媒體、變更音量及切換字幕。
- 如果影片中的資訊是完成工作流程的關鍵,請以轉錄稿等替代格式提供相同內容。
其他資源
如要進一步瞭解如何提高應用程式的無障礙程度,請參閱下列其他資源: