除了可組合函式所載的主要資訊 (例如 Text
可組合函式的文字字串) 之外,提供更多 UI 元素的補充資訊也相當實用。
關於 Compose 中元件意義和角色的資訊稱為語意,這是一種向無障礙、自動填入和測試等服務提供可組合項額外背景資訊的方式。舉例來說,相機圖示在視覺上可能只是一張圖片,但語意意義可能是「拍照」。
將適當的語意與適當的 Compose API 結合,即可向無障礙服務提供盡可能多的元件資訊,讓服務決定如何向使用者呈現。
Material、Compose UI 和 Foundation API 都內建語意,可根據其特定角色和功能進行調整,但您也可以根據特定需求,修改現有 API 的語意,或為自訂元件設定新的語意。
語意屬性
語意屬性可傳達對應可組合元件的意義。舉例來說,Text
可組合項包含語意屬性 text
,因為這是可組合項的含義。Icon
包含 contentDescription
屬性 (如果由開發人員設定),該屬性透過文字形式提供圖示的含義。
請考量語意屬性如何傳達可組合項的含義。請考慮使用 Switch
。使用者所看到的畫面如下:

Switch
處於「開啟」和「關閉」狀態。如要說明這個元素的含義,您可以說:「這是切換按鈕,它是一個可切換元素,目前處於『開啟』狀態。只要按一下即可與其互動。」
這就是語義屬性的用途。這個切換開關元素的語義節點包含下列屬性,用版面配置檢查器可以看到:

Switch
可組合項的語意屬性。Role
代表元素類型。StateDescription
說明瞭應該如何參考「開啟」狀態。根據預設,這是「開啟」一詞的本地化版本,但您可以根據背景資訊提供更明確的字詞 (例如「已啟用」)。ToggleableState
是切換按鈕的目前狀態。OnClick
屬性會參考與這個元素互動的方法。
追蹤應用程式中不同元件的語義屬性,藉此發掘許多強大的功能:
- 無障礙服務會使用這些屬性,代表畫面上顯示的 UI,並讓使用者與其互動。對於 Switch 可組合項,Talkback 可能會宣告:「開啟;切換;輕觸兩下即可切換」。使用者只要輕觸兩下螢幕即可關閉切換按鈕。
-
測試架構會使用屬性尋找節點、與節點互動以及進行宣告:
val mySwitch = SemanticsMatcher.expectValue( SemanticsProperties.Role, Role.Switch ) composeTestRule.onNode(mySwitch) .performClick() .assertIsOff()
建立在 Compose 基礎程式庫之上的可組合元件和修飾詞,預設會為您設定相關屬性。您可以視需要手動變更這些屬性,以改善特定用途的無障礙支援功能,或變更可組合項的合併或清除策略。
如要向無障礙服務傳達元件特定內容類型,您可以套用各種不同的語意。這些新增項目可支援主要語意資訊,並協助無障礙服務微調元件顯示、朗讀或互動的方式。
如需完整的語義屬性清單,請參閱 SemanticsProperties
物件。如需完整的無障礙操作清單,請參閱 SemanticsActions
物件。
標題
應用程式經常包含含有大量文字的畫面,例如長篇文章或新聞頁面,這些畫面通常會以標題劃分為不同的子區段:

無障礙功能的使用者無法順利瀏覽這類畫面。為改善瀏覽體驗,部分無障礙服務可讓使用者直接在各個部分或標題之間瀏覽。如要啟用這項功能,請定義元件的語意屬性,指出元件為 heading
:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
快訊和彈出式視窗
如果元件是警示或彈出式視窗 (例如 Snackbar
),您可能需要向無障礙服務發出信號,表示可以向使用者傳達新結構或內容更新。
您可以使用 liveRegion
語意屬性標示類似警示的元件。這可讓無障礙服務自動通知使用者此元件或其子項的變更:
PopupAlert( message = "You have a new message", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite } )
在大多數情況下,您應使用 liveRegionMode.Polite
,因為在這種情況下,使用者只需將注意力短暫轉移至畫面上的警示或重要變動內容。
請盡量少用 liveRegion.Assertive
,以免造成干擾。這項功能應用於必須讓使用者瞭解有時效性內容的情況:
PopupAlert( message = "Emergency alert incoming", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Assertive } )
請勿將即時區塊用於經常更新的內容,例如倒數計時器,以免不斷提供意見回饋而造成使用者負擔。
類似視窗的元件
類似 ModalBottomSheet
的窗格式自訂元件需要額外信號,才能與周圍內容區分開。為此,您可以使用 paneTitle
語意,讓無障礙服務能適當地呈現任何相關視窗或窗格變更,以及主要語意資訊:
ShareSheet( message = "Choose how to share this photo", modifier = Modifier .fillMaxWidth() .align(Alignment.TopCenter) .semantics { paneTitle = "New bottom sheet" } )
如需參考,請參閱 Material 3 如何使用 paneTitle
元件。
錯誤元件
針對其他類型的內容 (例如類似錯誤的元件),您可能需要為有無障礙需求的使用者擴充主要語意資訊。定義錯誤狀態時,您可以將 error
語意通知給無障礙服務,並提供擴充的錯誤訊息。
在這個範例中,TalkBack 會朗讀主要錯誤文字資訊,接著朗讀其他詳細訊息:
Error( errorText = "Fields cannot be empty", modifier = Modifier .semantics { error("Please add both email and password") } )
進度追蹤元件
針對追蹤進度的自訂元件,您可能會想通知使用者進度變更,包括目前進度值、範圍和步長。您可以使用 progressBarRangeInfo
語意來執行這項操作,確保無障礙服務能夠瞭解進度變更,並據此更新使用者。不同的輔助技術也可能會以獨特的方式提示增加和減少進度。
ProgressInfoBar( modifier = Modifier .semantics { progressBarRangeInfo = ProgressBarRangeInfo( current = progress, range = 0F..1F ) } )
清單和項目資訊
在包含許多項目的自訂清單和格線中,如果輔助服務也能收到更詳細的資訊,例如項目和索引的總數,可能會很有幫助。
在清單和項目上分別使用 collectionInfo
和 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) } ) } }
狀態說明
可組合項可定義語意的 stateDescription
,供 Android 架構用來解讀可組合項所處的狀態。舉例來說,可切換的可組合項可能處於「已勾選」或「未勾選」狀態。在某些情況下,您可能會想覆寫 Compose 使用的預設狀態說明標籤。您可以先明確指定狀態說明標籤,再將可組合項定義為可切換:
@Composable private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) { val stateSubscribed = stringResource(R.string.subscribed) val stateNotSubscribed = stringResource(R.string.not_subscribed) Row( modifier = Modifier .semantics { // Set any explicit semantic properties stateDescription = if (selected) stateSubscribed else stateNotSubscribed } .toggleable( value = selected, onValueChange = { onToggle() } ) ) { /* ... */ } }
自訂操作
自訂動作可用於更複雜的觸控螢幕手勢,例如滑動關閉或拖曳放置,因為這些動作對運動障礙或其他障礙的使用者來說,可能難以互動。
如要讓滑動關閉手勢更容易存取,您可以將其連結至自訂動作,並在該動作中傳遞關閉動作和標籤:
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() }
接著,TalkBack 等無障礙服務會醒目顯示元件,並提示選單中還有更多動作,代表滑動以關閉選單中的動作:

自訂動作的另一個用途是針對長清單中的項目,提供更多可用的動作,因為使用者可能會覺得逐一重複執行每個項目的動作很麻煩:

為了改善導覽體驗 (這對以互動為基礎的輔助技術特別有幫助,例如 Switch Access 或 Voice Access),您可以在容器上使用自訂動作,將動作從個別的遍歷移出,並放入單獨的動作選單:
ArticleListItemRow( modifier = Modifier .semantics { customActions = listOf( CustomAccessibilityAction( label = "Open article", action = { openArticle() true } ), CustomAccessibilityAction( label = "Add to bookmarks", action = { addToBookmarks() true } ), ) } ) { Article( modifier = Modifier.clearAndSetSemantics { }, onClick = openArticle, ) BookmarkButton( modifier = Modifier.clearAndSetSemantics { }, onClick = addToBookmarks, ) }
在這種情況下,請務必使用 clearAndSetSemantics
修飾符手動清除原始子項的語意,因為您會將這些子項移至自訂動作。
以切換控制功能為例,選取容器後會開啟選單,並列出可用的巢狀動作:


語意樹
Composition 描述了應用程式的 UI,可透過執行各個可組合元件產生。組合是一種樹狀結構,內含可描述 UI 的可組合元件。
Composition 旁邊有一個平行樹狀結構,也稱為「語義樹狀圖」。這個樹狀圖以 無障礙服務和測試架構能夠理解的替代方式描述 UI。無障礙服務會使用樹狀圖向有特定需求的使用者描述該應用程式。測試架構會使用樹狀圖與您的應用程式互動,並對其做出判斷提示。語意樹狀圖未包含如何繪製可組合元件的資訊,但包含可組合元件的語意含義資訊。

如果您的應用程式是由 Compose 基礎和材質庫的可組合元件和修飾元組成,系統會自動為您產生並填入語義樹狀圖。不過,當您新增自訂低層級可組合元件時,就必須手動提供其語意。在某些情況下,您的樹狀結構可能無法正確或完整反映螢幕上的元素含義,這時您只要調整樹狀結構即可。
以這個自訂日曆可組合元件為例:

在這個例子中,系統會使用Layout
可組合元件且直接繪製入Canvas
,從而將整個日曆作為單一低層級元件納入其中。如果您不採取任何其他行動,無障礙服務將無法收到有關可組合元件內容的資訊,也無法收到使用者在日曆中的選取資訊。舉例來說,如果使用者點選包含 17 的日期,無障礙架構只會接收整個日曆控制項的說明資訊。在這種情況下,TalkBack 無障礙功能服務只會說出「日曆」音訊,較好的情況下會說出「四月份日曆」,而使用者無法知道到底選取了哪一天。如要讓這元件更容易存取,您必須手動新增語義資訊。
合併及未合併的樹狀結構
如前文所述,UI 樹狀圖中每個可組合元件可能沒有或是有多個語義屬性設定。如果可組合元件沒有語意屬性設定,系統無法將其列入語意樹狀結構。那樣的話,語義樹狀圖僅包含真正含有語義含義的節點。但是,有時為了正確傳遞熒幕上呈現的含義,合併某些節點的子樹系並將其視為一體還是很有幫助的。那樣的話,您就可以將一組節點當做一個整體進行推理,而非單獨處理每個子節點。根據經驗,在使用無障礙服務時,這個樹狀圖中的每個節點都代表了一個可聚焦元素。
Button
就是這種可組合函式的範例。您可以將按鈕視為單一元素,即使它可能包含多個子節點:
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
在語意樹狀圖中,按鈕的子系屬性會被合併,且按鈕在樹狀圖中會顯示為單一的分葉節點:

可組合元件和修飾元可透過呼叫 Modifier.semantics
(mergeDescendants = true) {}
來合併其子系的語義屬性。如果將這個屬性設定為 true
,則表示應該合併語義屬性。在 Button
範例中,Button
可組合項在內部使用了含有 semantics
修飾符的 clickable
修飾符。因此,系統會合併按鈕的子系節點。請參閱無障礙說明文件,進一步瞭解何時應在可組合項中變更合併行為。
基礎與資料 Compose 程式庫中的數個修飾元和可組合元件具有該屬性設定。例如,clickable
和 toggleable
修飾元會自動合併它們的子系。此外,ListItem
可組合元件也會合併其子系。
檢查樹狀圖
語義樹狀圖其實是兩個不同的樹狀圖。其中一個是 已合併的語義樹狀圖,該樹狀圖在 mergeDescendants
設定為 true
時合併子系節點。另外還有一個未合併的語義樹狀圖,該樹狀圖不會套用合併規則,但會保留所有節點。無障礙服務會使用未合併的樹狀圖並套用自己的合併演算法,並將 mergeDescendants
屬性納入考量。根據預設,測試架構會使用合併的樹狀圖。
您可以使用 printToLog()
方法檢查這兩種樹狀圖。根據預設,和先前的範例一樣,系統會記錄已合併的樹狀圖。如要改為列印未合併的樹狀圖,請將 onRoot()
比對器的 useUnmergedTree
參數設為 true
:
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
版面配置檢查器可讓您在檢視模式篩選器中選取偏好的樹狀圖,以顯示合併和未合併的語義樹狀圖:

針對樹狀圖中的每個節點,版面配置檢查器會顯示其合併語義和屬性面板中該節點的語義設定:

根據預設,測試架構中的比對器會使用已合併的語義樹狀圖。因此,您可以透過比對 Button
內顯示的文字來與之互動:
composeTestRule.onNodeWithText("Like").performClick()
如要覆寫這項行為,請將比對器的 useUnmergedTree
參數設為 true
,做法與 onRoot
比對器相同。
調整樹狀圖
如上所述,您可以覆寫或清除特定語義屬性,或變更樹狀圖的合併行為。當您建立自訂可組合元件時,這一點尤其重要。如果沒有設定正確的屬性和合併行為,您的應用程式可能會無法存取,而測試行為可能與您預期的不同。如要進一步瞭解測試,請參閱測試指南。
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- Compose 中的無障礙功能
- Compose 中的 Material Design 2
- 測試 Compose 版面配置