ממשקי ה-API של Material, Compose UI ו-Foundation מיישמים ומציעים כברירת מחדל הרבה שיטות נגישות. הם מכילים סמנטיקה מובנית שמתאימה לתפקיד ולפונקציה הספציפיים שלהם. המשמעות היא שרוב התמיכה בנגישות מסופקת עם מעט עבודה נוספת או ללא עבודה נוספת.
שימוש בממשקי API המתאימים למטרה המתאימה פירושו שרכיבים בדרך כלל מגיעים עם התנהגויות נגישות מוגדרות מראש שמכסות תרחישי שימוש סטנדרטיים. עם זאת, תמיד כדאי לבדוק אם הגדרות ברירת המחדל האלה מתאימות לצרכי הנגישות שלכם. אם לא, בכתיבה בעזרת AI יש דרכים לעמוד בדרישות ספציפיות יותר.
הבנה של הסמנטיקה ודפוסי הנגישות שמוגדרים כברירת מחדל בממשקי API של Compose עוזרת לכם להשתמש בהם תוך התחשבות בנגישות. הוא גם עוזר לכם לתמוך בנגישות ברכיבים מותאמים אישית נוספים.
גדלים מינימליים של משטח המגע
כל אלמנט שמופיע במסך שמשתמשים יכולים ללחוץ עליו, לגעת בו או לבצע איתו אינטראקציה בכל דרך אחרת, צריך להיות גדול מספיק כדי לאפשר אינטראקציה אמינה. כשקובעים את הגודל של האלמנטים האלה, חשוב להגדיר את הגודל המינימלי ל-48dp כדי לפעול בהתאם להנחיות הנגישות של Material Design.
רכיבי Material – כמו Checkbox, RadioButton, Switch, Slider ו-Surface – מגדירים את הגודל המינימלי הזה באופן פנימי, אבל רק כשהרכיב יכול לקבל פעולות של משתמשים. לדוגמה, כשפרמטר onCheckedChange של Checkbox מוגדר לערך שאינו null, תיבת הסימון כוללת ריווח פנימי כדי שיהיו לה רוחב וגובה של לפחות 48dp.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
כשהפרמטר onCheckedChange מוגדר כ-null, הריווח לא נכלל כי אי אפשר ליצור אינטראקציה עם הרכיב ישירות.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
כשמטמיעים אמצעי בקרה לבחירה כמו Switch, RadioButton או Checkbox, בדרך כלל מעבירים את ההתנהגות הקליקבילית למאגר אב על ידי הגדרת הקריאה החוזרת (callback) של הקליק בתוכן הקומפוזבילי ל-null, והוספת משנה (modifier) מסוג 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) ) } }
כדי למנוע חפיפה אפשרית בין אזורי המגע של רכיבי Composable שונים, תמיד צריך להשתמש בגודל מינימלי מספיק גדול לרכיב ה-Composable. בדוגמה, המשמעות היא שימוש במקש הצירוף 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) ) } }
רכיבים גרפיים
כשמגדירים קומפוזיציה של 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 Framework שלאלמנט הזה אין פעולות או מצב משויכים.
@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, מגיעים עם סמנטיקה מוגדרת מראש שמתארת את ההתנהגות המובנית שלהם, ואפשר לשנות אותה באמצעות ממשקי API אחרים של Compose.
אלמנטים אינטראקטיביים
ממשקי ה-API של Material ו-Foundation Compose יוצרים רכיבי ממשק משתמש שהמשתמשים יכולים לקיים איתם אינטראקציה באמצעות ממשקי ה-API של clickable ו-toggleable modifier. רכיבים שאפשר ליצור איתם אינטראקציה עשויים לכלול כמה אלמנטים, ולכן התגים 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המשנה (לדוגמה, אם הוא מוגדר איפשהו בשכבה מקוננת נמוכה יותר),אבל עדיין תרצו לשנות את תווית ההודעה מברירת המחדל. כדי לעשות זאת, צריך לפצל את ההגדרה של clickable מהשינוי של ההודעה באמצעות משנה semantics והגדרת תווית הקליק שם, כדי לשנות את ייצוג הפעולה:
@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 } ) } ) }
לא צריך להעביר את פעולת הלחיצה פעמיים. ממשקי API קיימים של כתיבת הודעות, כמו clickable או Button, מטפלים בזה בשבילכם. לוגיקת המיזוג מוודאת שהתווית והפעולה של המשנה החיצוני ביותר מתייחסות למידע שמופיע. בדוגמה הקודמת, רכיב NestedArticleListItem מעביר אוטומטית את פעולת הלחיצה openArticle() לסמנטיקה שלו clickable. אפשר להשאיר את פעולת הלחיצה כ-null בפעולה השנייה של משנה הסמנטיקה. עם זאת,
תווית הקליק נלקחת מהמשנה הסמנטי השני
onClick(label = "Open this document") כי היא לא הופיעה בראשון.
יכול להיות שתיתקלו בתרחישים שבהם אתם מצפים שהסמנטיקה של רכיבי צאצא תמוזג עם הסמנטיקה של רכיב אב, אבל זה לא קורה. מידע נוסף זמין במאמר מיזוג וניקוי.
רכיבים בהתאמה אישית
כשיוצרים רכיב בהתאמה אישית, כדאי לעיין בהטמעה של רכיב דומה בספריית Material או בספריות אחרות של Compose. לאחר מכן, מחקים את התנהגות הנגישות שלו או משנים אותה בהתאם. לדוגמה, אם מחליפים את Checkbox של Material בהטמעה משלכם, עיון בהטמעה הקיימת של Checkbox יזכיר לכם להוסיף את משנה triStateToggleable, שמטפל במאפייני הנגישות של הרכיב. בנוסף, מומלץ להשתמש הרבה בשינויים של Foundation, כי הם כוללים שיקולי נגישות מובנים ושיטות עבודה מומלצות קיימות של Compose שמפורטות בקטע הזה.
בקטע בנושא סמנטיקה ברורה ומוגדרת יש גם דוגמה לרכיב מתג בהתאמה אישית, ובהנחיות לשימוש ב-API יש מידע מפורט יותר על תמיכה בנגישות ברכיבים בהתאמה אישית.
מומלץ בשבילך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- נגישות ב-Compose
- בדיקת הפריסה של חלון הכתיבה