تنفّذ واجهات برمجة التطبيقات Material وCompose UI وFoundation العديد من الممارسات التي تسهّل الاستخدام وتوفّرها تلقائيًا. وتتضمّن هذه العناصر دلالات مضمّنة تتوافق مع دورها ووظيفتها المحدّدين. وهذا يعني أنّه يتم توفير معظم ميزات تسهيل الاستخدام بدون الحاجة إلى بذل مجهود إضافي أو بمجهود بسيط.
يعني استخدام واجهات برمجة التطبيقات المناسبة للغرض المناسب أنّ المكوّنات تتضمّن عادةً سلوكيات محدّدة مسبقًا لتسهيل الاستخدام تغطّي حالات الاستخدام العادية. ومع ذلك، يُرجى التأكّد دائمًا مما إذا كانت هذه الإعدادات التلقائية تناسب احتياجاتك المتعلقة بسهولة الاستخدام. إذا لم يكن الأمر كذلك، يوفّر Compose طرقًا لتغطية متطلبات أكثر تحديدًا.
يساعدك فهم دلالات وأنماط تسهيل الاستخدام التلقائية في واجهات برمجة تطبيقات Compose على استخدامها مع مراعاة تسهيل الاستخدام. ويساعدك أيضًا في توفير إمكانية الوصول في المزيد من المكوّنات المخصّصة.
الحدّ الأدنى لأحجام مساحة اللمس
يجب أن يكون حجم أي عنصر على الشاشة كبيرًا بما يكفي لحدوث تفاعل موثوق به بحيث يمكن لأي مستخدم النقر عليه أو لمسه أو التفاعل معه. عند تحديد حجم هذه العناصر، احرص على ضبط الحد الأدنى للحجم على 48 بكسل مستقل الكثافة (dp) لاتباع إرشادات أدوات تمكين الوصول في التصميم المتعدد الأبعاد بشكل صحيح.
تضبط عناصر Material، مثل Checkbox وRadioButton وSwitch وSlider وSurface، هذا الحد الأدنى للحجم داخليًا، ولكن فقط عندما يكون العنصر قابلاً لتلقّي إجراءات المستخدم. على سبيل المثال، عندما يكون Checkbox مزوّدًا بالمعلَمة onCheckedChange التي تم ضبطها على قيمة غير فارغة، يتضمّن مربّع الاختيار مساحة متروكة ليكون عرضه وارتفاعه 48 وحدة بكسل مستقلة عن الكثافة على الأقل.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
عند ضبط المَعلمة onCheckedChange على القيمة null، لا يتم تضمين المساحة المتروكة لأنّه لا يمكن التفاعل مع المكوّن مباشرةً.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
عند تنفيذ عناصر التحكّم في الاختيار، مثل 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) } } }
عندما يكون حجم عنصر قابل للإنشاء وقابل للنقر أصغر من الحد الأدنى لحجم مساحة اللمس، يظل Compose يزيد حجم مساحة اللمس. ويتم ذلك من خلال توسيع حجم عنصر اللمس خارج حدود العنصر القابل للإنشاء.
يحتوي المثال التالي على 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) ) } }
لتجنُّب التداخل المحتمل بين مساحات اللمس الخاصة بعناصر مختلفة قابلة للإنشاء، احرص دائمًا على استخدام حد أدنى كبير بما يكفي للعنصر القابل للإنشاء. في المثال، يعني ذلك استخدام المعدِّل 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) ) } }
عناصر الرسومات
عند تحديد عنصر Image أو Icon قابل للإنشاء، لا توجد طريقة تلقائية تتيح لإطار عمل Android فهم ما يعرضه التطبيق. يجب تمرير وصف نصي للعنصر الرسومي.
تخيَّل شاشة يمكن للمستخدم من خلالها مشاركة الصفحة الحالية مع الأصدقاء. تحتوي هذه الشاشة على رمز مشاركة يمكن النقر عليه:
استنادًا إلى الرمز وحده، لا يمكن لإطار عمل 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 مخصّص بشكل أساسي للاستخدام مع العناصر الرسومية، مثل الصور. تتضمّن مكوّنات Material، مثل Button أو Text، والسلوكيات القابلة للتنفيذ، مثل clickable أو toggleable، دلالات أخرى محدّدة مسبقًا تصف سلوكها الجوهري، ويمكن تغييرها من خلال واجهات برمجة تطبيقات Compose الأخرى.
عناصر تفاعلية
تتيح واجهات برمجة التطبيقات Material وFoundation Compose إنشاء عناصر واجهة مستخدم يمكن للمستخدمين التفاعل معها من خلال واجهات برمجة التطبيقات المعدِّلة clickable وtoggleable. بما أنّ المكوّنات التفاعلية قد تتألف من عناصر متعددة، يدمج كل من clickable وtoggleable دلالات العناصر التابعة لهما تلقائيًا، وبالتالي يتم التعامل مع المكوّن على أنّه كيان منطقي واحد.
على سبيل المثال، قد يتألف عنصر Material Button من رمز ثانوي وبعض النصوص. بدلاً من التعامل مع العناصر التابعة بشكل فردي، تدمج الفئة Material
Button دلالات العناصر التابعة تلقائيًا، ما يتيح لخدمات تسهيل الاستخدام تجميعها وفقًا لذلك:
وبالمثل، يؤدي استخدام المعدِّل 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، مثل
clickable أو Button، تنفيذ ذلك نيابةً عنك. تتحقّق منطقية الدمج من أنّ التصنيف الخارجي للمعدِّل والإجراء يتم اتخاذهما للمعلومات المتوفّرة. في المثال السابق، يمرِّر العنصر NestedArticleListItem تلقائيًا إجراء النقر openArticle() إلى دلالاته clickable. يمكنك ترك إجراء النقر فارغًا في إجراء معدِّل الدلالات الثاني. ومع ذلك، يتم أخذ تصنيف النقرة من معدِّل الدلالات الثاني onClick(label = "Open this document") لأنّه لم يكن متوفّرًا في المعدِّل الأول.
قد تواجه سيناريوهات تتوقّع فيها دمج دلالات العناصر الفرعية في عنصر رئيسي، ولكن لا يحدث ذلك. يمكنك الاطّلاع على مقالة الدمج والمحو للحصول على معلومات أكثر تفصيلاً.
المكوّنات المخصّصة
عند إنشاء مكوّن مخصّص، راجِع عملية تنفيذ مكوّن مشابه في مكتبة Material أو مكتبات Compose الأخرى. بعد ذلك، حاكِ أو عدِّل سلوك تسهيل الاستخدام حسب الاقتضاء. على سبيل المثال، إذا كنت ستستبدل Checkbox في Material بتنفيذ خاص بك، سيذكّرك النظر إلى عملية التنفيذ الحالية لـ Checkbox بإضافة المعدِّل triStateToggleable الذي يتعامل مع خصائص تسهيل الاستخدام للمكوّن. بالإضافة إلى ذلك، استخدِم معدِّلات Foundation بشكل مكثّف، لأنّها تتضمّن اعتبارات مدمجة بشأن تسهيل الاستخدام وممارسات Compose الحالية الموضّحة في هذا القسم.
يمكنك أيضًا العثور على مثال لمكوّن تبديل مخصّص في قسم "محو الدلالات وتحديدها"، بالإضافة إلى معلومات أكثر تفصيلاً حول كيفية توفير إمكانية الوصول في المكوّنات المخصّصة ضمن إرشادات واجهة برمجة التطبيقات.
اقتراحات مخصصة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- تسهيل الاستخدام في Compose
- اختبار تصميم Compose