مبادئ تحسين إمكانية الوصول إلى التطبيق

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

توفّر Android عدة خدمات تسهيل استخدام على مستوى النظام، بما في ذلك ما يلي:

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

يمكن لكل من أفضل الممارسات هذه، الموضّحة في الأقسام التالية، تحسين إمكانية الوصول إلى تطبيقك بشكل أكبر:

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

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

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

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

توضّح الأقسام التالية عدة طرق أخرى لتصنيف العناصر.

العناصر القابلة للتعديل

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

في المثال التالي، يحتوي TextField على مَعلمة placeholder توفّر نصًا إرشاديًا.

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

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

في المثال التالي، يحتوي TextField على مَعلمة label توفّر وصفًا لتسهيل الاستخدام.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

لمزيد من المعلومات عن النص وبيانات أدخلها المستخدم، اطّلِع على مقالة إعداد حقول النص.

العناصر في مجموعة

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

على سبيل المثال، عند استخدام LazyColumn أو LazyRow، استخدِم المعدِّل semantics لتعيين collectionItemInfo فريد لكل عنصر، كما هو موضّح في المقتطف التالي:

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

لمزيد من المعلومات عن الخصائص الدلالية للقوائم والجداول، اطّلِع على مقالة معلومات القائمة والعناصر.

مجموعات المحتوى ذي الصلة

إذا كان تطبيقك يعرض عدة عناصر من واجهة المستخدم تشكّل مجموعة طبيعية، مثل تفاصيل أغنية أو سمات رسالة، رتِّب هذه العناصر ضمن حاوية رئيسية (مثل Column أو Row أو Box). استخدِم المعدِّل semantics للحاوية الرئيسية لضبط mergeDescendants على true.

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

في المقتطف التالي، يعمل العنصر المركّب Row كحاوية رئيسية. ضمن Row، هناك عناصر ذات صلة تعرض بيانات وصفية لمنشور مدونة، وهي صورة رمزية للمؤلف واسمه ووقت القراءة المقدَّر. يؤدي ضبط mergeDescendants على true إلى تجميع هذه العناصر الداخلية، ما يسمح لخدمات تسهيل الاستخدام بمعاملتها كوحدة واحدة.

@Composable
private fun PostMetadata(metadata: Metadata) {
    // Merge elements below for accessibility purposes
    Row(modifier = Modifier.semantics(mergeDescendants = true) {}) {
        Image(
            imageVector = Icons.Filled.AccountCircle,
            contentDescription = null // decorative
        )
        Column {
            Text(metadata.author.name)
            Text("${metadata.date}${metadata.readTimeMinutes} min read")
        }
    }
}

عند تجميع العناصر ذات الصلة كما في المثال السابق، اجعل الحاوية الرئيسية فقط تفاعلية. تجنَّب إضافة المعدِّلات clickable أو focusable إلى العناصر الفرعية الداخلية. بدلاً من ذلك، طبِّق المعدِّلات على العنصر Row أو Column الرئيسي.

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

ملاحظة: بشكل عام، عند إنشاء وصف محتوى لمجموعة، تجنَّب تجميع نص العناصر الفرعية. يؤدي ذلك إلى جعل وصف المجموعة غير ثابت، وعندما يتغيّر نص أحد العناصر الفرعية، قد لا يعود وصف المجموعة مطابقًا للنص المرئي.

في سياق قائمة أو جدول، قد يجمع قارئ الشاشة نص العُقد النصية الفرعية لعنصر قائمة أو جدول. من الأفضل تجنُّب تعديل هذا الإعلان.

لمزيد من المعلومات عن دمج الدلالات، اطّلِع على مقالة الدمج والإزالة.

العناوين ضمن النص

تستخدم بعض التطبيقات عناوين لتلخيص مجموعات من النصوص التي تظهر على الشاشة. إذا كان عنصر معيّن يمثّل عنوانًا، يمكنك الإشارة إلى الغرض منه لخدمات تسهيل الاستخدام من خلال ضبط السمة heading في المعدِّل semantics.

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

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

لمزيد من المعلومات عن السمة الدلالية heading، اطّلِع على مقالة العناوين.

عناوين لوحات تسهيل الاستخدام

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

لكي تفهم خدمات تسهيل الاستخدام سلوك اللوحة الذي يشبه النافذة، امنح لوحات تطبيقك عناوين وصفية. يمكن لخدمات تسهيل الاستخدام بعد ذلك تقديم معلومات أكثر دقة للمستخدمين عند تغيُّر مظهر اللوحة أو محتواها.

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

لمزيد من المعلومات عن السمة الدلالية paneTitle، اطّلِع على مقالة المكوّنات التي تشبه النافذة.

العناصر الزخرفية

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

بالنسبة إلى العناصر المركّبة Image أو Icon، اضبط contentDescription = null. بالنسبة إلى العناصر الزخرفية الأخرى التي لا توفّر أي سياق أو وظيفة، يمكنك استخدام hideFromAccessibility. تخبر هذه السمة الدلالية خدمات تسهيل الاستخدام بتجاهل العنصر.

إذا كان عنصر مركّب تفاعلي يحتوي على عناصر فرعية زخرفية غير تفاعلية، استخدِم clearAndSetSemantics للتأكّد من أنّ خدمات تسهيل الاستخدام لا تتنقّل بينها. يُرجى العِلم أنّ clearAndSetSemantics يمحو تمامًا الدلالات التلقائية لعنصر وعناصره الفرعية. يتيح لك ذلك تحديد عنصر جديد وموحّد لتسهيل الاستخدام. عادةً ما تستخدم هذا النهج للمكوّنات المخصّصة المعقّدة.

في المثال التالي، Icon وText هما عنصران فرعيان زخرفيان داخل مفتاح تبديل مخصّص. لمنع خدمات تسهيل الاستخدام من التنقّل بين هذه العناصر الفرعية بشكل فردي، يمكنك إزالة دلالاتها باستخدام clearAndSetSemantics على العنصر Row الرئيسي. يخبر هذا خدمات تسهيل الاستخدام بمعاملة العنصر Row بالكامل كمفتاح تبديل قابل للتنقّل:

// Developer might intend this to be a toggleable.
// Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied,
// a custom description is set, and a Role is applied.

@Composable
fun FavoriteToggle() {
    val checked = remember { mutableStateOf(true) }
    Row(
        modifier = Modifier
            .toggleable(
                value = checked.value,
                onValueChange = { checked.value = it }
            )
            .clearAndSetSemantics {
                stateDescription = if (checked.value) "Favorited" else "Not favorited"
                toggleableState = ToggleableState(checked.value)
                role = Role.Switch
            },
    ) {
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null // not needed here

        )
        Text("Favorite?")
    }
}

لمزيد من المعلومات عن إزالة الدلالات، اطّلِع على مقالة إزالة الدلالات وضبطها.

إضافة إجراءات تسهيل الاستخدام

من المهم التأكّد من أنّ مستخدمي خدمات تسهيل الاستخدام لديهم طريقة لإكمال جميع مسارات المستخدمين في تطبيقك.

إذا كان تفاعل العنصر المركّب المخصّص يغيّر حالة التطبيق بطريقة غير واضحة، قدِّم تصنيفات وصفية لإجراءات النقر العادية باستخدام مَعلمات مثل onClickLabel أو onLongClickLabel في Modifier.clickable أو Modifier.combinedClickable.

بالنسبة إلى التفاعلات المعقّدة التي لا يمكن ربطها بعمليات النقر العادية، استخدِم customActions.

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

في Compose، يمكنك تحديد إجراءات تسهيل استخدام مخصّصة من خلال السمة customActions في المعدِّل semantics، باستخدام CustomAccessibilityAction.

على سبيل المثال، إذا كان تطبيقك يسمح للمستخدمين بالتمرير سريعًا على عنصر لإغلاقه، يمكنك عرض هذه الوظيفة من خلال إجراء تسهيل استخدام مخصّص:

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

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

لمزيد من المعلومات عن الإجراءات المخصّصة، اطّلِع على مقالة الإجراءات المخصّصة.

توضيح الإجراءات المتاحة

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

لا يقدّم هذا الإعلان العام للمستخدم أي سياق حول ما يفعله إجراء اللمس مع الاستمرار.

لجعل هذا الإعلان أكثر فائدة، حدِّد وصفًا ذا معنى للإجراء.

في Compose، تحتوي معدِّلات التفاعل العادية، مثل clickable و combinedClickable، على مَعلمات مضمّنة (وهي onClickLabel و onLongClickLabel) يمكنك استخدامها لتقديم أوصاف للإجراءات، كما في المثال التالي:

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

يؤدي ذلك إلى إعلان TalkBack عن "فتح قائمة السياق"، ما يساعد المستخدمين في فهم الغرض من الإجراء.

يمكنك أيضًا تحديد تصنيف مباشرةً في المعدِّل semantics.

لمزيد من المعلومات عن الاستجابة لعمليات النقر، اطّلِع على مقالة النقر والضغط و العناصر التفاعلية.

استخدام ميزات تسهيل الاستخدام المضمّنة

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

في Jetpack Compose، استخدِم العناصر المركّبة المضمّنة، مثل Button وSwitch وCheckbox، لإنشاء واجهات مستخدم سهلة الاستخدام. تأتي هذه المكوّنات مُعدّة مسبقًا بمعدِّلات semantics، مثل role وstateDescription، التي يمكنك استخدامها لتسهيل استخدام تطبيقاتك.

تطبيق الدلالات على المكوّنات المخصّصة

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

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

على سبيل المثال، لنفترض أنّ هناك TriStateSwitch، وهو مفتاح تبديل بثلاث حالات (مفعّل وغير مفعّل وغير محدّد).

في حين أنّ المعدِّل toggleable العادي يفترض حالتين، يعالج المعدِّل triStateToggleable تعقيد الحالة الثالثة. ويضبط تلقائيًا لتسهيل الاستخدام Role (Switch) وState. بهذه الطريقة، تتلقّى خدمات تسهيل الاستخدام معلومات دقيقة، ولا تحتاج إلى تحديد الدلالات يدويًا.

يوضّح مقتطف الرمز التالي TriStateSwitch باستخدام هذا النهج:

@Composable
fun TriStateSwitch(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    // A real implementation would include custom drawing for the switch.
    // This example uses a Box to demonstrate the semantics.
    Box(
        modifier = modifier
            .size(width = 64.dp, height = 40.dp)
            // triStateToggleable handles the semantics (Role and State)
            // automatically, so explicit Modifier.semantics is not needed here.
            .triStateToggleable(
                state = state,
                onClick = onClick,
                role = Role.Switch
            )
            // Add visual feedback based on the state
            .background(
                when (state) {
                    ToggleableState.On -> Color.Green
                    ToggleableState.Off -> Color.Gray
                    ToggleableState.Indeterminate -> Color.Yellow
                }
            )
    )
}

// Usage within another composable:
var state by remember { mutableStateOf(ToggleableState.Off) }
TriStateSwitch(
    state = state,
    onClick = {
        state = when (state) {
            ToggleableState.Off -> ToggleableState.Indeterminate
            ToggleableState.Indeterminate -> ToggleableState.On
            ToggleableState.On -> ToggleableState.Off
        }
    }
)

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

استخدام إشارات أخرى غير اللون

لمساعدة المستخدمين الذين يعانون من مشاكل في رؤية الألوان، استخدِم إشارات أخرى غير اللون للتمييز بين عناصر واجهة المستخدم في شاشات تطبيقك. يمكن أن تتضمّن هذه الطرق استخدام أشكال أو أحجام مختلفة، أو توفير أنماط نصية أو مرئية، أو إضافة ملاحظات صوتية أو تستند إلى اللمس (الاهتزاز) لوضع علامة على اختلافات العناصر.

يوضّح الشكل 1 إصدارَين من نشاط. يستخدم أحد الإصدارَين اللون فقط للتمييز بين إجراءَين محتمَلَين في سير عمل. يستخدم الإصدار الآخر أفضل ممارسة تتضمّن الأشكال والنص بالإضافة إلى اللون لإبراز الاختلافات بين الخيارَين:

على اليسار، تظهر شاشة تحتوي على زرّين دائريين، أحدهما أخضر والآخر أحمر. على اليمين، تظهر الشاشة نفسها، ولكن تم تصنيف الزرّين الدائريين بنص ورموز ذات دلالة.
الشكل 1: أمثلة على إنشاء عناصر واجهة مستخدم باستخدام اللون فقط (على اليسار) واستخدام اللون والأشكال والنص (على اليمين).

تسهيل الوصول إلى محتوى الوسائط

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

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

مراجع إضافية

لمزيد من المعلومات عن تسهيل استخدام تطبيقك، اطّلِع على المراجع الإضافية التالية:

اختبارات الرموز

محتوى Views