يتم تلقائيًا تنفيذ سلوك قارئ الشاشة المتعلّق بتسهيل الاستخدام في تطبيق Compose بترتيب القراءة المتوقّع، والذي يكون عادةً من اليسار إلى اليمين ثم من أعلى إلى أسفل.
ومع ذلك، هناك بعض أنواع تخطيطات التطبيقات حيث لا يمكن للخوارزمية تحديد
ترتيب القراءة الفعلي بدون تلميحات إضافية. في التطبيقات المستندة إلى العرض، يمكنك
حلّ هذه المشاكل باستخدام السمتَين traversalBefore
وtraversalAfter
.
بدءًا من Compose 1.5، توفّر واجهة برمجة التطبيقات Compose واجهة برمجة تطبيقات مرنة بدرجة كبيرة ولكن
بنموذج مفاهيمي جديد.
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، وقيمة الساعة 1 هي traversalIndex
من 1.
وبهذه الطريقة، يتم ضبط الترتيب الذي تقرأه ميزة TalkBack. الآن، تتم قراءة الأرقام
داخل CircularLayout
بالترتيب المتوقع.
بما أنّ قيمة traversalIndexes
التي تم ضبطها مرتبطة فقط بالفهارس الأخرى ضمن المجموعة نفسها، تم الاحتفاظ ببقية ترتيب الشاشة. بمعنى آخر، لا تعدّل التغييرات الدلالية المعروضة في مقتطف الرمز السابق إلا الترتيب ضمن واجهة الساعة التي تم ضبط السمة isTraversalGroup = true
لها.
يُرجى العِلم أنّه بدون ضبط دلالات CircularLayout's
على isTraversalGroup =
true
، ستظل تغييرات traversalIndex
سارية. مع ذلك، بدون استخدام
CircularLayout
لربطهما، تتم قراءة الأرقام الاثني عشر من تصميم الساعة أخيرًا
بعد الاطّلاع على جميع العناصر الأخرى على الشاشة. ويحدث ذلك لأنّ جميع العناصر الأخرى تتضمّن traversalIndex
تلقائية تبلغ 0f
، وتتم قراءة العناصر النصية للساعة بعد جميع عناصر 0f
الأخرى.
مثال: تخصيص ترتيب الاجتياز لزر الإجراء الرئيسي
في هذا المثال، يتحكم traversalIndex
وisTraversalGroup
في ترتيب التمرير لزر الإجراء العائم (FAB) في Material Design. أساس هذا المثال هو التخطيط التالي:
يظهر التنسيق في هذا المثال تلقائيًا بترتيب 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
) إلى أنّ المربّع العائم يظهر قبل كل العناصر الأخرى التي تظهر على الشاشة.
بعد ذلك، يمكنك وضع المربع العائم والعناصر الأخرى في سقالة، مما ينفذ تخطيطًا للتصميم المتعدد الأبعاد:
@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