בנוסף למידע הראשי שרכיב ה-Composable מכיל, כמו מחרוזת טקסט של רכיב Text
, יכול להיות שיהיה שימושי לקבל מידע נוסף על רכיבי ממשק המשתמש.
המידע על המשמעות והתפקיד של רכיב ב-Compose נקרא סמנטיקה. הוא מאפשר לספק הקשר נוסף על רכיבים קומפוזביליים לשירותים כמו נגישות, מילוי אוטומטי ובדיקות. לדוגמה, סמל המצלמה יכול להיות פשוט תמונה מבחינה חזותית, אבל המשמעות הסמנטית שלו יכולה להיות 'צילום תמונה'.
שילוב של הסמנטיקה המתאימה עם ממשקי ה-API המתאימים של Compose מאפשר לספק לשירותי הנגישות כמה שיותר מידע על הרכיב, והם מחליטים איך לייצג אותו למשתמש.
ממשקי ה-API של Material ו-Compose UI ו-Foundation מגיעים עם סמנטיקה מובנית שמתאימה לתפקיד ולפונקציה הספציפיים שלהם, אבל אפשר גם לשנות את הסמנטיקה הזו בממשקי API קיימים או להגדיר סמנטיקה חדשה לרכיבים מותאמים אישית, בהתאם לדרישות הספציפיות שלכם.
מאפיינים סמנטיים
מאפיינים סמנטיים מעבירים את המשמעות של הרכיב הניתן לקיבוץ התואם. לדוגמה, הרכיב הניתן לקישור Text
מכיל מאפיין סמנטי text
, כי זהו המשמעות של הרכיב הזה. Icon
מכיל מאפיין contentDescription
(אם המפתח הגדיר אותו) שמציג בטקסט את משמעות הסמל.
כדאי לחשוב איך מאפייני הסמנטיקה מעבירים את המשמעות של רכיב ה-Composable. כדאי לשקול Switch
. כך זה נראה למשתמש:

Switch
במצבים 'מופעל' ו'מושבת'.כדי לתאר את המשמעות של האלמנט הזה, אפשר לומר: "זהו מתג, שהוא אלמנט שניתן להפעיל ולהשבית במצב 'מופעל'. אפשר ללחוץ עליו כדי לבצע פעולות איתו".
זה בדיוק המטרה של מאפייני הסמנטיקה. הצומת הסמנטי של רכיב המתג הזה מכיל את המאפיינים הבאים, כפי שמוצגים בתצוגה החזותית של כלי בדיקת הפריסה:

Switch
קומפוזיבי.הערך Role
מציין את סוג הרכיב. השדה StateDescription
מתאר איך צריך להפנות למצב 'מופעל'. כברירת מחדל, זוהי גרסה מותאמת לשוק המקומי של המילה 'מופעל', אבל אפשר להפוך אותה לספציפית יותר (לדוגמה, 'מופעל') על סמך ההקשר. הערך ToggleableState
הוא המצב הנוכחי של המתג. המאפיין OnClick
מפנה לשיטה שמשמשת לאינטראקציה עם האלמנט הזה.
מעקב אחרי מאפייני הסמנטיקה של כל רכיב מורכב באפליקציה מאפשר לכם ליהנות מאפשרויות רבות ויעילות:
- שירותי הנגישות משתמשים במאפיינים האלה כדי לייצג את ממשק המשתמש שמוצג במסך ולאפשר למשתמשים לקיים איתו אינטראקציה. אם מדובר במתג שאפשר להרכיב, יכול להיות שמערכת TalkBack תקריא: "מופעל; מתג; מקישים הקשה כפולה כדי להעביר למצב אחר". המשתמש יכול להקיש הקשה כפולה על המסך כדי להשבית את המתג.
-
מסגרת הבדיקה משתמשת במאפיינים כדי למצוא צמתים, לבצע אינטראקציה איתם ולבצע טענות נכוֹנוּת (assertions):
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" } )
לקבלת מידע נוסף, אפשר לעיין במאמר איך paneTitle
משמש ב-Material 3 לרכיבים שלו.
רכיבי השגיאה
בסוגים אחרים של תוכן, כמו רכיבים שדומים לשגיאות, כדאי להרחיב את המידע הסמנטי הראשי למשתמשים עם צרכים של נגישות.
כשמגדירים מצבי שגיאה, אפשר להודיע לשירותי הנגישות על הסמנטיקה של 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 מדגיש את הרכיב ומציין שיש פעולות נוספות שזמינות בתפריט שלו, ומציג את הפעולה של החלקה כדי לסגור:

מקרה לדוגמה נוסף לשימוש בפעולות בהתאמה אישית הוא רשימות ארוכות עם פריטים שיש להם יותר פעולות זמינות, כי יכול להיות שיהיה משעמם למשתמשים לעבור על כל פעולה לכל פריט בנפרד:

כדי לשפר את חוויית הניווט, ששימושית במיוחד לטכנולוגיות מסייעות שמבוססות על אינטראקציה כמו 'גישה באמצעות מתג' או 'גישה קולית', אפשר להשתמש בפעולות בהתאמה אישית בקונטיינר כדי להעביר פעולות מטרaversal בודד לתפריט פעולות נפרד:
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 יש עץ מקביל שנקרא עץ הסמנטיקה. בעץ הזה מתוארת ממשק המשתמש שלכם באופן חלופי שקל להבין אותו בשירותי הנגישות ובמסגרת הבדיקות. שירותי הנגישות משתמשים בעץ כדי לתאר את האפליקציה למשתמשים עם צורך ספציפי. מסגרת הבדיקה משתמשת בעץ כדי לקיים אינטראקציה עם האפליקציה ולבצע טענות נכוֹנוּת לגביה. עץ הסמנטיקה לא מכיל מידע על אופן הציור של הרכיבים הניתנים לקישור, אבל הוא מכיל מידע על המשמעות הסמנטית של הרכיבים הניתנים לקישור.

אם האפליקציה מורכבת מרכיבים ומערכי מודולים מ-Compose Foundation ומספריית Material, עץ הסמנטיקה יתמלא וייווצר באופן אוטומטי. עם זאת, כשמוסיפים רכיבים מותאמים אישית ברמה נמוכה, צריך לספק את הסמנטיקה שלהם באופן ידני. יכול להיות גם מצב שבו העץ לא מייצג בצורה נכונה או מלאה את המשמעות של הרכיבים במסך. במקרה כזה, תוכלו לשנות את העץ.
לדוגמה, הנה יומן מותאם אישית שאפשר ליצור ממנו קומפוזיציה:

בדוגמה הזו, כל היומן מיושם כרכיב מורכב יחיד ברמה נמוכה, באמצעות הרכיב המורכב Layout
וציור ישירות ב-Canvas
.
אם לא תבצעו פעולה נוספת, שירותי הנגישות לא יקבלו מספיק מידע על התוכן של הרכיב הניתן להתאמה אישית ועל הבחירה של המשתמש ביומן. לדוגמה, אם משתמש לוחץ על היום שמכיל את ה-17, מסגרת הנגישות מקבלת רק את פרטי התיאור של כל אמצעי הבקרה של לוח השנה. במקרה כזה, שירות הנגישות TalkBack יכריז על 'יומן' או, גרוע יותר, על 'יומן אפריל', והמשתמש יצטרך לנסות לנחש איזה יום נבחר. כדי לשפר את הנגישות של הרכיב הניתן לקישור, צריך להוסיף מידע סמנטי באופן ידני.
עץ מיזוג ועץ ללא מיזוג
כפי שצוין קודם, לכל רכיב שאפשר ליצור בו רכיבים אחרים בעץ של ממשק המשתמש יכולים להיות אפס מאפייני סמנטיקה או יותר. אם לא מוגדרים מאפייני סמנטיקה ברכיב הניתן לקישור, הוא לא נכלל בעץ הסמנטיקה. כך, עץ הסמנטיקה מכיל רק את הצמתים שמכילים בפועל משמעות סמנטית. עם זאת, לפעמים כדי להעביר את המשמעות הנכונה של מה שמוצג במסך, כדאי גם למזג עצי משנה מסוימים של צמתים ולטפל בהם כעץ אחד. כך תוכלו להסיק מסקנות לגבי קבוצת צמתים כמכלול, במקום לטפל בכל צומת צאצא בנפרד. ככלל, כל צומת בעץ הזה מייצג רכיב שאפשר להעביר אליו את המיקוד כשמשתמשים בשירותי הנגישות.
דוגמה לרכיב כזה היא Button
. אפשר להתייחס ללחצן כרכיב יחיד, גם אם הוא מכיל כמה צמתים צאצאים:
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
בעץ הסמנטיקה, המאפיינים של הצאצאים של הלחצן ממוזגים, והלחצן מוצג כצומת עלה יחיד בעץ:

רכיבים קומפוזביליים ורכיבי שינוי יכולים להצביע על כך שהם רוצים למזג את מאפייני הסמנטיקה של הצאצאים שלהם על ידי קריאה ל-Modifier.semantics
(mergeDescendants = true) {}
. הגדרת המאפיין הזה ל-true
מציינת שצריך למזג את מאפייני הסמנטיקה. בדוגמה של Button
, ה-composable של Button
משתמש ב-modifier clickable
באופן פנימי, שכולל את ה-modifier semantics
. לכן, הצמתים הצאצאים של הלחצן מוזגו.
במסמכי העזרה בנושא נגישות מוסבר מתי צריך לשנות את התנהגות המיזוג ב-composable.
הנכס הזה מוגדר במספר מודיפיקרים ורכיבים בספריות Foundation ו-Material Compose. לדוגמה, המשתנים המשתנים clickable
ו-toggleable
ישלבו באופן אוטומטי את הצאצאים שלהם. בנוסף, ה-composable של ListItem
ישלב את הצאצאים שלו.
בדיקת העץ
עץ הסמנטיקה הוא למעשה שני עצים שונים. יש עץ סמנטיקה המיזוג, שממזג צמתים צאצאים כשהערך של mergeDescendants
מוגדר כ-true
.
יש גם עץ סמנטיקה לא משולב, שבו לא מתבצע המיזוג אבל כל הצמתים נשארים ללא שינוי. שירותי הנגישות משתמשים בעץ שלא עבר מיזוג ומחילים את אלגוריתמי המיזוג שלהם, תוך התחשבות במאפיין mergeDescendants
. מסגרת הבדיקה משתמשת בעץ הממוזג כברירת מחדל.
אפשר לבדוק את שני העצים באמצעות השיטה printToLog()
. כברירת מחדל, כמו בדוגמאות הקודמות, הנתונים של העץ הממוזג נרשמים ביומן. כדי להדפיס במקום זאת את העץ שלא עבר מיזוג, מגדירים את הפרמטר useUnmergedTree
של המתאמים onRoot()
לערך true
:
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
ב-Layout Inspector אפשר להציג גם את עץ הסמנטיקה הממוזג וגם את עץ הסמנטיקה הלא ממוזג, על ידי בחירה של העץ המועדף במסנן התצוגה:

בכל צומת בעץ, בכלי לבדיקת הפריסה מוצגים גם הסמנטיקה הממוזגת וגם הסמנטיקה שמוגדרת בצומת הזה בחלונית המאפיינים:

כברירת מחדל, האלגוריתמים להתאמה במסגרת הבדיקה משתמשים בעץ הסמנטיקה הממוזג.
לכן אפשר לבצע פעולות ב-Button
על ידי התאמה לטקסט שמוצג בתו:
composeTestRule.onNodeWithText("Like").performClick()
כדי לשנות את ההתנהגות הזו, מגדירים את הפרמטר useUnmergedTree
של המתאמים לערך true
, כמו במתאם onRoot
.
התאמת העץ
כפי שצוין קודם, אפשר לשנות את התנהגות המיזוג של העץ, לשנות או לנקות מאפייני סמנטיקה מסוימים. הדבר רלוונטי במיוחד כשיוצרים רכיבים מותאמים אישית. בלי להגדיר את המאפיינים וההתנהגות המתאימים למיזוג, יכול להיות שלא תהיה גישה לאפליקציה, והבדיקות עשויות להתנהג בצורה שונה ממה שציפיתם. מידע נוסף על בדיקות זמין במדריך לבדיקות.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- נגישות ב-Compose
- עיצוב Material 2 ב-Compose
- בדיקת הפריסה של 'כתיבה'