تعديل ترتيب التنقّل

ترتيب التنقّل هو الترتيب الذي تنتقل به خدمات تسهيل الاستخدام من خلال عناصر واجهة المستخدم. في تطبيق إنشاء، يتم ترتيب العناصر بترتيب القراءة المتوقّع، وهو عادةً من اليسار إلى اليمين، ثم من الأعلى إلى الأسفل. ومع ذلك، هناك بعض السيناريوهات التي قد تحتاج فيها ميزة "الإنشاء" إلى تلميحات إضافية لتحديد ترتيب القراءة الصحيح.

isTraversalGroup وtraversalIndex هما سمتان دلاليتان تسمحان لك بالتأثير في ترتيب التنقّل في خدمات تسهيل الاستخدام في السيناريوهات التي لا تكون فيها خوارزمية الترتيب التلقائية في ميزة "الإنشاء" كافية. يحدِّد isTraversalGroup المجموعات المهمة من الناحية الدلالية التي تحتاج إلى تخصيص، في حين يعدِّل traversalIndex ترتيب العناصر الفردية ضمن هذه المجموعات. يمكنك استخدام isTraversalGroup وحده للإشارة إلى أنّه يجب اختيار جميع العناصر ضمن مجموعة معًا، أو مع traversalIndex لإجراء المزيد من التخصيص.

استخدِم isTraversalGroup وtraversalIndex في تطبيقك للتحكّم في ترتيب التنقّل لقارئ الشاشة.

تجميع العناصر للتنقّل

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
        )
    }
}

ينتج الرمز البرمجي مخرجات مشابهة لما يلي:

تنسيق يتضمّن عمودَين من النص، يظهر في العمود الأيسر "هذه
  الجملة في العمود الأيسر" وفي العمود الأيمن "هذه الجملة على اليمين"
الشكل 1. تنسيق يتضمّن جملتَين (واحدة في عمود الأيسر وواحدة في العمود الأيمن)

وبما أنّه لم يتم ضبط أيّ دلالات، فإنّ السلوك التلقائي لقارئ الشاشة هو التنقّل في العناصر من اليسار إلى اليمين ومن الأعلى إلى الأسفل. بسبب هذا الإعداد التلقائي، يقرأ تطبيق 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 فقط على Column أي أثر، على سبيل المثال، ما لم يتم ضبط isTraversalGroup على العمود أيضًا.

يوضّح المثال التالي كيفية استخدام traversalIndex و isTraversalGroup معًا.

خلفية شاشة الساعة هي سيناريو شائع لا يعمل فيه ترتيب التنقّل العادي. يعرض هذا القسم مثالاً على أداة اختيار الوقت، حيث يمكن للمستخدم التنقّل في الأرقام على خلفية شاشة الساعة واختيار أرقام خانتَي الساعة والدقيقة.

خلفية شاشة ساعة مع أداة اختيار الوقت فوقها
الشكل 2. صورة لخلفية شاشة ساعة

في المقتطف المبسّط التالي، هناك 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 الأخرى.

الاعتبارات المتعلّقة بواجهة برمجة التطبيقات

يُرجى مراعاة ما يلي عند استخدام واجهات برمجة التطبيقات للتنقّل:

  • يجب ضبط isTraversalGroup = true على العنصر الرئيسي الذي يحتوي على العناصر grouped.
  • يجب ضبط traversalIndex على مكوّن فرعي يحتوي على دلالات، وسيتم اختياره من خلال خدمات تسهيل الاستخدام.
  • تأكّد من أنّ جميع العناصر التي تفحصها في zIndex المستوى نفسه، لأنّ ذلك يؤثر أيضًا في الدلالات وترتيب التنقّل.
  • تأكَّد من عدم دمج أيّ دلالات بدون داعٍ، لأنّ ذلك قد يؤثر في المكوّنات التي يتم تطبيق مؤشرات التنقّل عليها.