الإعدادات التلقائية لواجهة برمجة التطبيقات

تطبّق واجهات برمجة التطبيقات Material وCompose UI وFoundation العديد من الممارسات التي توفّر إمكانية الاستخدام الميسّر تلقائيًا. وتحتوي هذه العناصر على دلالات مضمّنة تتبع دورها ووظيفة المحددة، ما يعني أنّه يتم توفير معظم ميزات تسهيل الاستخدام بجهد إضافي بسيط أو بدون أي جهد إضافي.

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

تساعدك معرفة الدلالات والنماذج التلقائية لتسهيل الاستخدام في واجهات برمجة التطبيقات Compose في معرفة كيفية استخدامها مع وضع تسهيل الاستخدام في الاعتبار، بالإضافة إلى إتاحة تسهيل الاستخدام في المزيد من المكوّنات المخصّصة.

الحد الأدنى لحجم مساحات اللمس

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

تضبط مكوّنات Material Design، مثل Checkbox وRadioButton وSwitch Slider وSurface، الحدّ الأدنى هذا للحجم داخليًا، ولكن فقط عندما يمكن للعنصر تلقّي إجراءات المستخدم. على سبيل المثال، عندما يكون Checkbox يحتوي على مَعلمة onCheckedChange تم ضبطها على قيمة غير فارغة، يتضمّن مربّع الاختيار مَعلمة تحكّم في المسافة بين عناصر الصفحة ليكون العرض والارتفاع 48 وحدة كثافة بكسل على الأقل.

@Composable
private fun CheckableCheckbox() {
    Checkbox(checked = true, onCheckedChange = {})
}

مربّع اختيار مع الحشو التلقائي بعرض وارتفاع 48 وحدة كثافة بكسل
الشكل 1. مربّع اختيار مع مساحة بادئة تلقائية

عند ضبط المَعلمة onCheckedChange على القيمة null، لا يتم تضمين الحشو، لأنّه لا يمكن التفاعل مع المكوّن مباشرةً.

@Composable
private fun NonClickableCheckbox() {
    Checkbox(checked = true, onCheckedChange = null)
}

مربّع اختيار بدون مساحة فارغة
الشكل 2. مربّع اختيار بدون مسافة بادئة

عند تنفيذ عناصر التحكّم في الاختيار، مثل Switch أو RadioButton أو Checkbox، يمكنك عادةً رفع السلوك القابل للنقر إلى حاوية رئيسية من خلال ضبط دالة الاستدعاء للنقر على العنصر القابل للإنشاء على null، وإضافة تعديل 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)
        }
    }
}

مربّع اختيار بجانب النص "خيار" الذي يتم اختياره وإلغاء اختياره
الشكل 3. مربّع اختيار يتضمّن سلوكًا يمكن النقر عليه

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

يحتوي المثال التالي على رمز 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)
        )
    }
}

مربّع صغير جدًا قابل للنقر يتم توسيعه إلى هدف لمس أكبر من خلال النقر بجانب المربّع
الشكل 4. مربّع صغير جدًا قابل للنقر يتم توسيعه إلى مساحة لمس أكبر

لمنع التداخل المحتمل بين مناطق اللمس في العناصر المركّبة المختلفة، يجب دائمًا استخدام الحد الأدنى من الحجم الكبير بما يكفي للعنصر المركّب. في المثال، يعني ذلك استخدام المُعدِّل 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)
        )
    }
}

تمّ زيادة حجم المربّع الصغير جدًا من المثال السابق لإنشاء استهداف لمس أكبر.
الشكل 5. ناحية لمس مربّع أكبر

العناصر الرسومية

عند تحديد عنصر قابل للتركيب من النوع Image أو Icon، لا تتوفّر طريقة تلقائية لفِرق عمل إطار عمل Android لفهم ما يعرضه التطبيق. يجب تقديم وصف نصي للعنصر الرسومي.

تخيل شاشة يمكن للمستخدم من خلالها مشاركة الصفحة الحالية مع الأصدقاء. تحتوي هذه الشاشة على رمز مشاركة يمكن النقر عليه:

شريط يتضمّن أربعة رموز قابلة للنقر، مع تمييز رمز "المشاركة"
الشكل 6. صف من الرموز القابلة للنقر مع اختيار رمز "المشاركة"

استنادًا إلى الرمز وحده، لا يمكن لإطار عمل 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 بأنّ هذا العنصر ليس لديه إجراءات أو حالة مرتبطة به.

@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 بشكل أساسي لعناصر الرسومات، مثل الصور. إنّ المكونات الأساسية، مثل Button أو Text، والسلوكيات التي يمكن اتّخاذها، مثل clickable أو toggleable، تأتي مع دلالات مفروضة أخرى تصف سلوكها الأساسي، ويمكن تغييرها من خلال واجهات برمجة تطبيقات Compose الأخرى.

عناصر تفاعلية

تُنشئ واجهات برمجة التطبيقات Material وFoundation Compose عناصر واجهة مستخدِم يمكن للمستخدمين التفاعل معها من خلال واجهات برمجة التطبيقات الخاصة بالمُعدِّلات clickable وtoggleable. بما أنّه قد تتألف المكوّنات القابلة للتفاعل من عناصر متعددة، يدمج clickable و toggleable دلالات العناصر الثانوية تلقائيًا، بحيث يتم التعامل مع المكوّن ككيان منطقي واحد.

على سبيل المثال، قد يتألّف عنصر Button من رمز فرعي وبعض النصوص. بدلاً من التعامل مع العناصر الفرعية كعناصر فردية، يدمج زر Material دلالات عناصره الفرعية تلقائيًا، حتى تتمكّن خدمات تسهيل الاستخدام من تجميعها وفقًا لما يلي:

الأزرار التي تحتوي على دلالات عناصر فرعية غير مدمجة مقارنةً بالعناصر المدمجة
الشكل 7. الأزرار التي تحتوي على دلالات عناصر فرعية غير مدمجة مقارنةً بالعناصر المدمجة

وبالمثل، يؤدي استخدام المُعدِّل 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
                }
            )
        }
    )
}

في هذه الحالة، لا تحتاج إلى تمرير إجراء النقر مرّتين، لأنّ واجهتَي برمجة التطبيقات الحاليتَين Compose API، مثل clickable أو Button، تتولّى ذلك نيابةً عنك. ويعود السبب في ذلك إلى أنّ منطق الدمج يضمن استخدام تصنيف وإجراء المُعدِّل الخارجيَين للمعلومات المتوفّرة.

في المثال السابق، يتم تمرير إجراء النقر على openArticle() إلى أسفل الصفحة من قِبل NestedArticleListItem تلقائيًا إلى دلالة clickable، ويمكن تركه فارغًا في إجراء مُعدِّل الدلالة الثاني. ومع ذلك، يتم أخذ تصنيف النقرة من مُعدِّل الدلالات الثاني onClick(label = "Open this article")، لأنّه لم يكن متوفّرًا في المُعدِّل الأول.

قد تواجه سيناريوهات تتوقّع فيها دمج سمات العناصر الفرعية في سمة عنصر رئيسي، ولكن لا يحدث ذلك. اطّلِع على دمج الرسائل وحذفها لمزيد من المعلومات المفصّلة.

المكوّنات المخصّصة

بالنسبة إلى المكوّنات المخصّصة، كقاعدة عامة، اطّلِع على تنفيذ مكوّن مشابه في مكتبة Material أو مكتبات Compose الأخرى، وقلِّد أو عدِّل سلوك تسهيل الاستخدام عندما يكون من المنطقي إجراء ذلك.

على سبيل المثال، إذا كنت تستبدل رمز Material Checkbox بتطبيقك الخاص، سيذكّرك الاطّلاع على تطبيق مربّع الاختيار الحالي بإضافة المُعدِّل triStateToggleable الذي يعالج سمات تسهيل الاستخدام لهذا المكوّن.

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

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