يتم تلقائيًا تنفيذ سلوك قارئ الشاشة لتسهيل الاستخدام في تطبيق 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 ) } }
تُنتج التعليمة البرمجية مخرجات مشابهة لما يلي:
![تخطيط بعمودين من النص، مع قراءة العمود الأيسر "هذه
في العمود الأيسر' والعمود الأيمن بعنوان "هذه الجملة على اليمين".](https://developer.android.com/static/develop/ui/compose/images/a11y-istraversalgroup-example.png?authuser=19&hl=ar)
نظرًا لعدم تعيين دلالات دلالية، يكون السلوك التلقائي لقارئ الشاشة هو لاجتياز العناصر من اليسار إلى اليمين ومن أعلى إلى أسفل. بسبب ذلك الإعداد التلقائي، تقرأ ميزة 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
معًا.
مثال: اجتياز واجهة الساعة
واجهة الساعة هي سيناريو شائع حيث لا يكون ترتيب الاجتياز القياسي عملك. يوضح المثال في هذا القسم أداة اختيار الوقت حيث يمكن للمستخدم اجتياز من خلال الأرقام على واجهة الساعة واختيار أرقام للساعة والدقيقة الخانات.
![واجهة ساعة فوقها أداة اختيار وقت](https://developer.android.com/static/develop/ui/compose/images/a11y-clock-face.png?authuser=19&hl=ar)
في المقتطف المُبسَّط التالي، هناك 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
في
ترتيب الاجتياز لزر الإجراء العائم في Material Design (FAB). الأساس
في هذا المثال هو التخطيط التالي:
![تخطيط به شريط تطبيق علوي ونموذج نص وزر إجراء عائم
شريط التطبيق السفلي.](https://developer.android.com/static/develop/ui/compose/images/a11y-fab-example.png?authuser=19&hl=ar)
بشكل تلقائي، يكون التنسيق الوارد في هذا المثال على النحو التالي في ميزة 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 مع العناصر بالترتيب التالي:
زر الإجراء الرئيسي ← شريط التطبيق العلوي ← نماذج النصوص من 0 إلى 6 ← شريط التطبيق السفلي
مصادر إضافية
- أدوات تسهيل الاستخدام: المفاهيم الأساسية الأساليب الشائعة لجميع تطوير تطبيقات Android
- إنشاء تطبيقات يسهل الوصول إليها: خطوات رئيسية التي يمكنك اتخاذها لتسهيل استخدام تطبيقك
- مبادئ تحسين التطبيق أدوات تسهيل الاستخدام: المبادئ الأساسية يجب أخذه في الاعتبار عند العمل على تسهيل استخدام تطبيقك
- اختبار تسهيل الاستخدام: اختبار مبادئ وأدوات تسهيل الاستخدام في Android