Material、Compose UI 和 Foundation API 預設會實作並提供許多無障礙做法。這些元件包含內建語意,會遵循其特定角色和功能。這表示您幾乎不需要額外作業,就能提供大部分的無障礙支援。
只要針對適當用途使用適當的 API,元件通常會隨附預先定義的無障礙行為,涵蓋標準用途。不過,請務必仔細檢查這些預設值是否符合您的無障礙需求。如果沒有,Compose 也提供其他方法,可滿足更具體的需求。
瞭解 Compose API 的預設無障礙語意和模式,有助於您在使用時考量無障礙功能。此外,您也可以在更多自訂元件中支援無障礙功能。
觸控目標大小下限
任何使用者可點擊、輕觸或進行互動的螢幕元素,都必須設為適當大小,方便使用者進行互動。設定這些元素的大小時,請務必將大小下限設為 48dp,以便正確遵循「Material Design 無障礙指南」。
Material 元件 (例如 Checkbox、RadioButton、Switch、Slider 和 Surface) 會在內部設定這個大小下限,但僅限元件可以接收使用者動作時。舉例來說,如果 Checkbox 的 onCheckedChange 參數設為非空值,核取方塊就會包含至少 48 dp 的寬度和高度。
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }

當 onCheckedChange 參數設為空值時,系統不會納入邊框間距,因為該元件無法直接互動。
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }

導入 Switch、RadioButton 或 Checkbox 等選取控制項時,您通常會將可點擊的行為推送至父項容器,方法是將可組合項的點擊回呼設為 null,然後在可組合父項中新增 toggleable 或 selectable 輔助鍵。
@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) } } }

如果可點擊的可組合項大小小於最低觸控目標大小,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) ) } }
為避免不同可組合項的觸控區域重疊,請一律針對可組合項使用夠大的最小尺寸。在範例中,這代表使用 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) ) } }
如果元素必須保持較小的可見大小,請改用 Material 3 的 minimumInteractiveComponentSize 修飾符。它會在每個維度中保留至少 48 dp 的版面配置空間,並將元素置於該空間的中央,因此元素會保持其繪製大小,而周圍的元素會移動以騰出空間。修飾符不會展開觸控目標本身,而是在版面配置中預留空間,以便進行上述展開作業。Checkbox 等 Material 元件會在內部使用這個修飾符。請將其放在任何大小修飾符之前,因為在它之前的大小修飾符會限制它可以保留的空間。
@Composable private fun MinimumInteractiveBox() { var clicked by remember { mutableStateOf(false) } Row(verticalAlignment = Alignment.CenterVertically) { Box( Modifier .clickable { clicked = !clicked } .minimumInteractiveComponentSize() .size(24.dp) .background(if (clicked) Color.DarkGray else Color.Black) ) Text("Option") } }
圖像元素
定義 Image 或 Icon 可組合項時,Android 架構無法自動瞭解應用程式顯示的內容。您必須傳送圖形元素的文字說明。
請設想一個螢幕,可供使用者與好友分享目前的頁面。這個畫面包含可點擊的共用圖示:

單憑圖示,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 主要用於圖片等圖形元素。Material 元件 (例如 Button 或 Text) 和可執行的行為 (例如 clickable 或 toggleable) 具有其他預先定義的語意,用於描述其內在行為,並可透過其他 Compose API 變更。
互動式元素
Material 和 Foundation Compose API 會建立使用者可透過 clickable 和 toggleable 修飾符 API 互動的 UI 元素。由於可互動元件可能包含多個元素,clickable 和 toggleable 預設會合併子項的語意,因此元件會視為一個邏輯實體。
舉例來說,Material Button 可能包含子項圖示和一些文字。Material Button 預設會合併子項語意,而非將子項視為個別項目,因此無障礙服務可以據此將子項分組:

同樣地,使用 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 (例如 clickable 或 Button) 會為您處理這項作業。合併邏輯會驗證是否針對現有資訊採用最外層的修飾符標籤和動作。在上述範例中,NestedArticleListItem 會自動將 openArticle() 點擊動作傳遞至其 clickable 語意。您可以在第二個語意修飾符動作中,將點擊動作留空。不過,點擊標籤會取自第二個語意修飾符 onClick(label = "Open this document"),因為第一個修飾符中沒有這個標籤。
您可能會遇到預期子項語意會合併至父項語意,但並未發生的情況。詳情請參閱「合併和清除」。
自訂元件
建構自訂元件時,請查看 Material 程式庫或其他 Compose 程式庫中類似元件的實作方式。然後視情況模擬或修改其無障礙行為。舉例來說,如果您將 Material Checkbox 替換成自己的實作項目,查看現有的 Checkbox 實作項目時,系統會提醒您新增 triStateToggleable 修飾符,用於處理元件的無障礙屬性。此外,請多多利用基礎修飾符,因為這類修飾符內建無障礙功能考量,以及本節涵蓋的現有 Compose 做法。
您也可以在「清除及設定語意」一節中找到自訂切換元件的範例,並在 API 指南中進一步瞭解如何在自訂元件中支援無障礙功能。
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- Compose 中的無障礙功能
- 測試 Compose 版面配置