為了滿足使用者的無障礙需求,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 中,您可以使用 CustomAccessibilityAction,透過 semantics 修飾符中的 customActions 屬性定義自訂無障礙動作。
舉例來說,如果應用程式允許使用者滑動項目來關閉,您可以透過自訂無障礙動作公開這項功能:
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) 就足夠了,因為它們會自動為您填入語意樹狀結構。
不過,有些元件需要比標準修飾符提供的資訊更具體。在這些情況下,請尋找專用修飾符 (例如 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 顯示同一活動的兩個版本。其中一個版本只使用顏色來區分工作流程中的兩個可能動作。另一個版本則採用最佳做法,除了顏色以外還利用形狀和文字來凸顯兩個選項的差異:
提高媒體內容的無障礙程度
如果您開發的應用程式包含媒體內容 (例如短片或音訊錄音),請設法為具有不同類型無障礙需求的使用者提供支援,協助他們理解這些內容。請特別嘗試下列做法:
- 加入控制項,讓使用者暫停或停止播放媒體、變更音量及切換字幕。
- 如果影片中的資訊是完成工作流程的關鍵,請以轉錄稿等替代格式提供相同內容。
其他資源
如要進一步瞭解如何提高應用程式的無障礙程度,請參閱下列其他資源: