כברירת מחדל, מוטמעת ההתנהגות של קורא מסך נגישות באפליקציית 'כתיבה'
בסדר הקריאה הצפוי, שהוא בדרך כלל משמאל לימין, ולאחר מכן מלמעלה למטה.
עם זאת, יש סוגים מסוימים של פריסות אפליקציה שבהן האלגוריתם לא יכול לקבוע
את סדר הקריאה בפועל, ללא רמזים נוספים. באפליקציות מבוססות-צפייה, אפשר
לפתור בעיות כאלה באמצעות המאפיינים traversalBefore
ו-traversalAfter
.
החל מגרסה 1.5 של 'כתיבה', ממשק API גמיש באותה מידה, אבל עם
תפיסת עולם חדשה.
isTraversalGroup
ו-traversalIndex
הם מאפיינים סמנטיים
מאפשרות לשלוט בסדר המיקוד בנגישות וב-TalkBack במקרים שבהם
אלגוריתם המיון שמוגדר כברירת מחדל אינו מתאים. isTraversalGroup
מזהה
קבוצות בעלות חשיבות סמנטית, בעוד traversalIndex
משנה את הסדר
רכיבים נפרדים בתוך הקבוצות האלה. אפשר להשתמש ב-isTraversalGroup
בלבד,
או עם traversalIndex
להתאמה אישית נוספת.
שימוש ב-isTraversalGroup
וב-traversalIndex
ב-
אפליקציה כדי לשלוט בסדר המעבר של קורא המסך.
קיבוץ רכיבים עם isTraversalGroup
isTraversalGroup
הוא נכס בוליאני שמגדיר אם סמנטיקה
הצומת הוא קבוצת מעבר. צומת מהסוג הזה הוא צומת שהפונקציה שלו היא למלא בקשות
בתור גבול או גבול בארגון הצאצא של הצומת.
אם מגדירים את isTraversalGroup = true
בצומת, כל הצאצאים של הצומת הזה.
מבקרים לפני שעוברים לרכיבים אחרים. אפשר להפעיל את isTraversalGroup
צמתים שלא ניתן להתמקד בהם בקורא מסך, כמו 'עמודות', 'שורות' או 'תיבות'.
הדוגמה הבאה משתמשת ב-isTraversalGroup
. הוא פולט ארבעה רכיבי טקסט.
שני רכיבים משמאל שייכים לרכיב CardBox
אחד, ושני רכיבים ימניים
שייכים לרכיב CardBox
אחר:
// CardBox() function takes in top and bottom sample text. @Composable fun CardBox( topSampleText: String, bottomSampleText: String, modifier: Modifier = Modifier ) { Box(modifier) { Column { Text(topSampleText) Text(bottomSampleText) } } } @Composable fun TraversalGroupDemo() { val topSampleText1 = "This sentence is in " val bottomSampleText1 = "the left column." val topSampleText2 = "This sentence is " val bottomSampleText2 = "on the right." Row { CardBox( topSampleText1, bottomSampleText1 ) CardBox( topSampleText2, bottomSampleText2 ) } }
הקוד יוצר פלט שדומה לזה:
בגלל שלא הוגדר סמנטיקה, התנהגות ברירת המחדל של קורא המסך היא כדי לעבור בין אלמנטים משמאל לימין ומלמעלה למטה. לכן כברירת מחדל, TalkBack מקריא את קטעי המשפטים בסדר שגוי:
"המשפט הזה נמצא" ← "המשפט הזה הוא" ← "העמודה השמאלית". → "ב נכון".
כדי לסדר את המקטעים בצורה נכונה, צריך לשנות את קטע הקוד המקורי להגדרה
isTraversalGroup
עד true
:
@Composable fun TraversalGroupDemo2() { val topSampleText1 = "This sentence is in " val bottomSampleText1 = "the left column." val topSampleText2 = "This sentence is" val bottomSampleText2 = "on the right." Row { CardBox( // 1, topSampleText1, bottomSampleText1, Modifier.semantics { isTraversalGroup = true } ) CardBox( // 2, topSampleText2, bottomSampleText2, Modifier.semantics { isTraversalGroup = true } ) } }
בגלל שהפרמטר isTraversalGroup
מוגדר באופן ספציפי בכל CardBox
, CardBox
הגבולות חלים בזמן מיון הרכיבים שלהם. במקרה הזה, החלון השמאלי
קוראים קודם CardBox
, ואחריהם CardBox
מימין.
עכשיו, TalkBack מקריא את קטעי המשפטים בסדר הנכון:
"המשפט הזה נמצא" ← "העמודה השמאלית". ← "המשפט הזה הוא" → "ב נכון".
התאמה אישית נוספת של סדר המעבר
traversalIndex
הוא נכס צף שמאפשר להתאים אישית את TalkBack
סדר המעבר. אם קיבוץ רכיבים ביחד לא מספיק כדי ש-TalkBack
פועלות כראוי, צריך להשתמש ב-traversalIndex
בשילוב עם
isTraversalGroup
כדי להתאים אישית את הסדר של קוראי המסך.
המאפיין traversalIndex
כולל את המאפיינים הבאים:
- רכיבים עם ערכי
traversalIndex
נמוכים יותר מקבלים עדיפות ראשונה. - הוא יכול להיות חיובי או שלילי.
- ערך ברירת המחדל הוא
0f
. - משפיעה רק על צמתים עם קורא מסך שניתן להתמקד בהם, כמו רכיבים במסך כמו
טקסט או לחצנים. לדוגמה, אם מגדירים רק את הערך
traversalIndex
בעמודה, אין להם השפעה, אלא אם מוגדר גםisTraversalGroup
על העמודה.
הדוגמה הבאה מראה איך אפשר להשתמש ב-traversalIndex
וב-
isTraversalGroup
ביחד.
דוגמה: תצוגת שעון לחצי
תצוגת שעון היא תרחיש נפוץ שבו סדר המעבר הרגיל לא בעבודה. הדוגמה בקטע הזה היא בורר זמן, שבו משתמש יכול לעבור בין המספרים בתצוגת השעון ובוחרים ספרות עבור השעה והדקה משבצות זמן.
בקטע הקוד הפשוט הבא, יש CircularLayout
שבו 12
המספרים נשלפים, החל מ-12 ונעים בכיוון השעון סביב המעגל:
@Composable fun ClockFaceDemo() { CircularLayout { repeat(12) { hour -> ClockText(hour) } } } @Composable private fun ClockText(value: Int) { Box(modifier = Modifier) { Text((if (value == 0) 12 else value).toString()) } }
בגלל שתצוגת השעון לא נקראת באופן לוגי עם ערכי ברירת המחדל משמאל לימין התכונה TalkBack מקריאה את המספרים מלמעלה למטה, בסדר יורד. לתיקון הבעיה זאת, השתמשו בערך המונה המצטבר, כפי שמוצג בקטע הקוד הבא:
@Composable fun ClockFaceDemo() { CircularLayout(Modifier.semantics { isTraversalGroup = true }) { repeat(12) { hour -> ClockText(hour) } } } @Composable private fun ClockText(value: Int) { Box(modifier = Modifier.semantics { this.traversalIndex = value.toFloat() }) { Text((if (value == 0) 12 else value).toString()) } }
כדי להגדיר כראוי את סדר המעבר, תחילה צריך להפוך את CircularLayout
קבוצת מעבר ולהגדיר את isTraversalGroup = true
. לאחר מכן, מכיוון שכל טקסט של שעון
שצייר על הפריסה, מגדירים את traversalIndex
התואם למונה
עם ערך מסוים.
מכיוון שערך המונה גדל כל הזמן,
הגודל של traversalIndex
גדול יותר ככל שמוסיפים למסך מספרים. ערך השעון הוא 0
הערך של traversalIndex
הוא 0, והערך traversalIndex
של השעון הוא 1.
כך נקבע הסדר שבו TalkBack מקריא אותן. עכשיו, המספרים
בתוך CircularLayout
נקראות בסדר הצפוי.
בגלל שהערכים של traversalIndexes
שהוגדרו מתייחסים רק לערכים של
או אינדקסים בתוך אותה קיבוץ, שאר סדר המסכים
נשמר. כלומר, השינויים הסמנטיים שמוצגים בקוד הקודם
קטע הקוד ישנה רק את הסדר בתצוגת השעון שכוללת
isTraversalGroup = true
הוגדרה.
חשוב לשים לב שהשינויים של traversalIndex
עדיין חלים בלי להגדיר את הסמנטיקה של CircularLayout's
ל-isTraversalGroup =
true
. אבל בלי
CircularLayout
כדי לקשר ביניהם, 12 הספרות של תצוגת השעון נקראות
לבסוף, אחרי שכל שאר הרכיבים במסך כבר ביקרו. מצב כזה קורה
מכיוון שלכל שאר הרכיבים יש ערך traversalIndex
של 0f
כברירת מחדל,
רכיבי טקסט השעון נקראים אחרי כל שאר רכיבי 0f
.
דוגמה: התאמה אישית של סדר המעבר ללחצן פעולה צף
בדוגמה הזו, traversalIndex
ו-isTraversalGroup
שולטים
סדר המעבר של לחצן פעולה צף מסוג Material Design (FAB). הבסיס
של הדוגמה הזו היא הפריסה הבאה:
כברירת מחדל, הפריסה בדוגמה הזו מבוססת על הסדר הבא של TalkBack:
סרגל מוביל של האפליקציה ← טקסטים לדוגמה 0 עד 6 ← לחצן פעולה צף (FAB) ← למטה סרגל האפליקציות
מומלץ שקורא המסך יתמקד קודם ב-FAB. כדי להגדיר
traversalIndex
ברכיב Material כמו FAB, מבצעים את הפעולות הבאות:
@Composable fun FloatingBox() { Box(modifier = Modifier.semantics { isTraversalGroup = true; traversalIndex = -1f }) { FloatingActionButton(onClick = {}) { Icon(imageVector = Icons.Default.Add, contentDescription = "fab icon") } } }
בקטע הקוד הזה, יצירת תיבה עם
הטווח isTraversalGroup
הוגדר לערך true
והוגדר traversalIndex
באותה תיבה
(הערך -1f
נמוך מערך ברירת המחדל של 0f
) פירושו שהתיבה הצפה
מופיע לפני כל שאר הרכיבים במסך.
בשלב הבא, אפשר להכניס את התיבה הצפה ורכיבים אחרים לפיגום, משתמשת בפריסה של Material Design:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun ColumnWithFABFirstDemo() { Scaffold( topBar = { TopAppBar(title = { Text("Top App Bar") }) }, floatingActionButtonPosition = FabPosition.End, floatingActionButton = { FloatingBox() }, content = { padding -> ContentColumn(padding = padding) }, bottomBar = { BottomAppBar { Text("Bottom App Bar") } } ) }
TalkBack מקיים אינטראקציה עם הרכיבים בסדר הבא:
FAB ← הסרגל העליון של האפליקציה ← דגימות טקסטים 0 עד 6 ← הסרגל התחתון של האפליקציה
מקורות מידע נוספים
- נגישות: מושגים בסיסיים שיטות הנפוצות לכל פיתוח אפליקציות ל-Android
- יצירת אפליקציות נגישות: שלבים חשובים שאפשר לבצע כדי שהאפליקציה תהיה נגישה יותר
- עקרונות לשיפור האפליקציה נגישות: עקרונות מרכזיים חשוב לזכור שמשפרים את הנגישות של האפליקציה
- בדיקות נגישות: עקרונות בדיקה וכלים לנגישות ב-Android