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

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

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

  • TalkBack: يساعد الأشخاص الذين يعانون من ضعف البصر أو المكفوفين. تُعلن عن المحتوى من خلال الصوت المركّب وتنفيذ إجراءات على التطبيق استجابةً لإيماءات المستخدم.
  • الوصول عبر مفتاح تحكّم: يساعد الأشخاص الذين يعانون من إعاقات حركية. يسلط الضوء على العناصر التفاعلية وتنفيذ إجراءات استجابةً لضغط المستخدم على أحد الأزرار. تسمح بـ التحكم في الجهاز باستخدام زر أو زرين فقط.

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

كل واحدة من أفضل الممارسات هذه، والموضحة في الأقسام التالية، يمكن أن يساعد ذلك في تحسين تسهيل استخدام تطبيقك بشكل أكبر:

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

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

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

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

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

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

<!-- The hint text for en-US locale would be
     "Apartment, suite, or building". -->
<EditText
   android:id="@+id/addressLine2"
   android:hint="@string/aptSuiteBuilding" ... />

في هذه الحالة، يجب أن يكون للكائن View السمة android:labelFor. إلى معرّف العنصر EditText. لمزيد من التفاصيل، يُرجى الاطّلاع على ما يلي: .

أزواج من العناصر حيث يصف أحدهما الآخر

من الشائع أن يكون للعنصر EditText مطابق كائن View الذي يصف ما يجب على المستخدمين لإدخالها في العنصر EditText. ويمكنك الإشارة إلى هذه العلاقة من خلال تحديد السمة android:labelFor لكائن View.

ويظهر مثال على تصنيف أزواج العناصر هذه في المقتطف التالي:


<!-- Label text for en-US locale would be "Username:" -->
<TextView
   android:id="@+id/usernameLabel" ...
   android:text="@string/username"
   android:labelFor="@+id/usernameEntry" />

<EditText
   android:id="@+id/usernameEntry" ... />

<!-- Label text for en-US locale would be "Password:" -->
<TextView
   android:id="@+id/passwordLabel" ...
   android:text="@string/password
   android:labelFor="@+id/passwordEntry" />

<EditText
   android:id="@+id/passwordEntry"
   android:inputType="textPassword" ... />

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

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

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

لإجراء ذلك، عيّن وصف المحتوى كجزء من تنفيذ المحوّل، باعتباره كما هو موضح في مقتطف الرمز التالي:

Kotlin

data class MovieRating(val title: String, val starRating: Integer)

class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
        RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {

    class MyRatingViewHolder(val ratingView: ImageView) :
            RecyclerView.ViewHolder(ratingView)

    override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
        val ratingData = myData[position]
        holder.ratingView.contentDescription = "Movie ${position}: " +
                "${ratingData.title}, ${ratingData.starRating} stars"
    }
}

Java

public class MovieRating {
    private String title;
    private int starRating;
    // ...
    public String getTitle() { return title; }
    public int getStarRating() { return starRating; }
}

public class MyMovieRatingsAdapter
        extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> {
    private MovieRating[] myData;


    public static class MyRatingViewHolder extends RecyclerView.ViewHolder {
        public ImageView ratingView;
        public MyRatingViewHolder(ImageView iv) {
            super(iv);
            ratingView = iv;
        }
    }

    @Override
    public void onBindViewHolder(MyRatingViewHolder holder, int position) {
        MovieRating ratingData = myData[position];
        holder.ratingView.setContentDescription("Movie " + position + ": " +
                ratingData.getTitle() + ", " + ratingData.getStarRating() +
                " stars")
    }
}

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

إذا كان تطبيقك يعرض العديد من عناصر واجهة المستخدم التي تشكِّل مجموعة طبيعية، مثل تفاصيل أغنية أو سمات رسالة، رتب هذه العناصر ضمن التي تكون عادةً فئة فرعية من ViewGroup. ضبط الحاوية كائن android:screenReaderFocusable إلى true، وقيمة كل كائن داخلي android:focusable إلى false. بهذه الطريقة، يمكن لخدمات سهولة الوصول تقديم العناصر' أوصاف المحتوى الواحد تلو الآخر في إشعار واحد يساعد هذا توحيد العناصر ذات الصلة مستخدمي التكنولوجيا المساعدة اكتشاف المعلومات التي تظهر على الشاشة بشكل أكثر كفاءة.

يتضمن المقتطف التالي أجزاءً من المحتوى مرتبطة بواحد. الآخر، وبالتالي فإن عنصر الحاوية، وهو مثيل لـ ConstraintLayout، له تم ضبط السمة android:screenReaderFocusable على true والداخلية عناصر TextView تم ضبط السمة android:focusable الخاصة بها على false:

<!-- In response to a single user interaction, accessibility services announce
     both the title and the artist of the song. -->
<ConstraintLayout
    android:id="@+id/song_data_container" ...
    android:screenReaderFocusable="true">

    <TextView
        android:id="@+id/song_title" ...
        android:focusable="false"
        android:text="@string/my_song_title" />
    <TextView
        android:id="@+id/song_artist"
        android:focusable="false"
        android:text="@string/my_songwriter" />
</ConstraintLayout>

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

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

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

المجموعات المتداخلة

إذا كانت واجهة تطبيقك تعرض معلومات متعددة الأبعاد، مثل قائمة يومية بفعاليات المهرجان، استخدِم android:screenReaderFocusable على حاويات المجموعة الداخلية. يوفر نظام التسمية هذا أفضل التوازن بين عدد الإعلانات اللازمة لاكتشاف المحتوى ومدة كل إعلان

يوضح مقتطف الرمز التالي إحدى الطرق لتصنيف المجموعات داخل مجموعات أكبر:

<!-- In response to a single user interaction, accessibility services
     announce the events for a single stage only. -->
<ConstraintLayout
    android:id="@+id/festival_event_table" ... >
    <ConstraintLayout
        android:id="@+id/stage_a_event_column"
        android:screenReaderFocusable="true">

        <!-- UI elements that describe the events on Stage A. -->

    </ConstraintLayout>
    <ConstraintLayout
        android:id="@+id/stage_b_event_column"
        android:screenReaderFocusable="true">

        <!-- UI elements that describe the events on Stage B. -->

    </ConstraintLayout>
</ConstraintLayout>

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

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

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

عناوين الأجزاء المخصّصة لتسهيل الاستخدام

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

لتحديد عنوان الجزء، استخدم android:accessibilityPaneTitle كما هو موضح في المقتطف التالي:

<!-- Accessibility services receive announcements about content changes
     that are scoped to either the "shopping cart view" section (top) or
     "browse items" section (bottom) -->
<MyShoppingCartView
     android:id="@+id/shoppingCartContainer"
     android:accessibilityPaneTitle="@string/shoppingCart" ... />

<MyShoppingBrowseView
     android:id="@+id/browseItemsContainer"
     android:accessibilityPaneTitle="@string/browseProducts" ... />

عناصر زخرفية

إذا كان أحد العناصر في واجهة المستخدم متوفرًا فقط للمسافات أو المظهر المرئي فقط قم بتعيين android:importantForAccessibility إلى "no".

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

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

إتاحة الوصول إلى جميع الإجراءات

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

باستخدام إجراءات إمكانية الوصول، يمكن للتطبيق توفير طرق بديلة للمستخدمين لإكمال إجراء ما.

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

Kotlin

ViewCompat.addAccessibilityAction(
    // View to add accessibility action
    itemView,
    // Label surfaced to user by an accessibility service
    getText(R.id.archive)
) { _, _ ->
    // Same method executed when swiping on itemView
    archiveItem()
    true
}

Java

ViewCompat.addAccessibilityAction(
    // View to add accessibility action
    itemView,
    // Label surfaced to user by an accessibility service
    getText(R.id.archive),
    (view, arguments) -> {
        // Same method executed when swiping on itemView
        archiveItem();
        return true;
    }
);

With the custom accessibility action implemented, users can access the action through the actions menu.

Make available actions understandable

When a view supports actions such as touch & hold, an accessibility service such as TalkBack announces it as "Double tap and hold to long press."

This generic announcement doesn't give the user any context about what a touch & hold action does.

To make this announcement more descriptive, you can replace the accessibility action’s announcement like so:

Kotlin

ViewCompat.replaceAccessibilityAction(
    // View that contains touch & hold action
    itemView,
    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK,
    // Announcement read by TalkBack to surface this action
    getText(R.string.favorite),
    null
)

Java

ViewCompat.replaceAccessibilityAction(
    // View that contains touch & hold action
    itemView,
    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK,
    // Announcement read by TalkBack to surface this action
    getText(R.string.favorite),
    null
);

This results in TalkBack announcing "Double tap and hold to favorite," helping users understand the purpose of the action.

Extend system widgets

Note: When you design your app's UI, use or extend system-provided widgets that are as far down Android's class hierarchy as possible. System-provided widgets that are far down the hierarchy already have most of the accessibility capabilities your app needs. It's easier to extend these system-provided widgets than to create your own from the more generic View, ViewCompat, Canvas, and CanvasCompat classes.

If you must extend View or Canvas directly, which might be necessary for a highly customized experience or a game level, see Make custom views more accessible.

This section uses the example of implementing a special type of Switch called TriSwitch while following best practices around extending system widgets. A TriSwitch object works similarly to a Switch object, except that each instance of TriSwitch allows the user to toggle among three possible states.

Extend from far down the class hierarchy

The Switch object inherits from several framework UI classes in its hierarchy:

View
↳ TextView
  ↳ Button
    ↳ CompoundButton
      ↳ Switch

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

  • إجراءات إمكانية الوصول: معلومات للنظام حول طريقة تسهيل الاستخدام خدمات تحاكي كل إدخال محتمل للمستخدم تم تنفيذه على TriSwitch الخاص بك. (مُكتسَب من View).
  • أحداث إمكانية الوصول: معلومات لخدمات تسهيل الاستخدام حول جميع طريقة ممكنة لتغيير مظهر كائن TriSwitch عندما تظهر التحديثات أو التحديثات. (مُكتسَب من View).
  • الخصائص: تفاصيل حول كل كائن TriSwitch، مثل لمحتوى أي نص يعرضه. (مُكتسَب من TextView).
  • معلومات الولاية: وصف للحالة الحالية لكائن TriSwitch على سبيل المثال "محدد" أو "غير محدد". (مُكتسَب من CompoundButton).
  • وصف نصي للولاية: شرح نصي لما تعنيه كل ولاية يمثله. (مُكتسَب من Switch).

هذا السلوك الناتج عن Switch وفئاته الفائقة هو تقريبًا السلوك نفسه لـ TriSwitch عنصر وبالتالي، قد تؤثر عملية التنفيذ نركز على زيادة عدد الحالات المحتملة من اثنين إلى ثلاث.

تحديد الأحداث المخصّصة

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

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

طريقة عمل هذا المبدأ مع كائنات TriSwitch

على عكس جسم Switch العادي، يؤدي النقر على جسم TriSwitch في الدوران إلى ثلاث حالات محتملة. وبالتالي، تكون إمكانية الوصول المقابلة في ACTION_CLICK يجب تحديث الإجراء:

Kotlin

class TriSwitch(context: Context) : Switch(context) {
    // 0, 1, or 2
    var currentState: Int = 0
        private set

    init {
        updateAccessibilityActions()
    }

    private fun updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label) {
            view, args -> moveToNextState()
        })
    }

    private fun moveToNextState() {
        currentState = (currentState + 1) % 3
    }
}

Java

public class TriSwitch extends Switch {
    // 0, 1, or 2
    private int currentState;

    public int getCurrentState() {
        return currentState;
    }

    public TriSwitch() {
        updateAccessibilityActions();
    }

    private void updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label, (view, args) -> moveToNextState());
    }

    private void moveToNextState() {
        currentState = (currentState + 1) % 3;
    }
}

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

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

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

الشكل 1. أمثلة على إنشاء عناصر واجهة المستخدم باستخدام الألوان فقط (إلى اليسار) واستخدام اللون والأشكال والنص (اليمين).

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

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

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

مصادر إضافية

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

الدروس التطبيقية حول الترميز

مشاركات المدونة