Accessibility Trait: الجوهر والأنواع وكيفية العمل في التطوير

المؤلف: IT Sectr نُشر: 2026-05-16 وقت القراءة: 9 دق

Accessibility Trait هي خاصية لعنصر iOS تحدد دوره وسلوكه لبرنامج VoiceOver. يخبر التريت قارئ الشاشة كيف يجب نطق العنصر وما هي الإيماءات المتاحة: هل هو زر أم عنوان أم رابط أم حقل بحث. وفقًا لـ Apple UIAccessibilityTraits، 2024، يدعم النظام أكثر من 15 ثابتًا يمكن دمجها باستخدام قناع بت. التريت المختار بشكل صحيح يوفر ما يصل إلى 50% من وقت التنقل لمستخدمي VoiceOver.

النقاط الرئيسية

  • Accessibility Trait — دور عنصر iOS لبرنامج VoiceOver؛ يتم تعيينه عبر ثوابت UIAccessibilityTraits
  • يمكن دمج التريتات باستخدام عامل التشغيل | لإنشاء أدوار معقدة (زر + محدد)
  • يمكن أن يحتوي كل عنصر على عدة تريتات في وقت واحد، ولكن ليس أكثر من 3-4 لتجنب الارتباك
  • التريت غير الصحيح (مثل StaticText لزر) يفسد سيناريو التفاعل: لا يعرف المستخدم ما إذا كانت الإيماءة متاحة
  • في Android، النظير هو سمات role و className في AccessibilityNodeInfo

ما هو Accessibility Trait

Accessibility Trait هي علامة يتم تعيينها على عنصر UIView لتحديد دوره الدلالي لبرنامج VoiceOver. التريت هو أحد المكونات الثلاثة لثلاثية إمكانية الوصول من Apple: Label (الاسم)، Hint (الوصف)، Trait (الدور). يستخدم iOS قناع بت UIAccessibilityTraits (UInt64)، حيث يتوافق كل بت مع دور محدد. يقرأ VoiceOver الدور بعد Label و Hint: «زر إرسال. سيفتح نموذجًا» — تمت إضافة «زر» بفضل تريت UIAccessibilityTraitButton.

بشكل افتراضي، يحصل UIButton على UIAccessibilityTraitButton، ويحصل UILabel على UIAccessibilityTraitStaticText، ويحصل UIImageView على UIAccessibilityTraitImage. عند استخدام عناصر تحكم مخصصة، يجب على المطور تعيين التريت يدويًا. Apple Human Interface Guidelines، 2024، تسمي هذا «واحدة من أكثر الخطوات أهمية لضمان إمكانية الوصول».

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

التنفيذ الفني لـ UIAccessibilityTraits

UIAccessibilityTraits هو typealias UInt64. كل تريت هو ثابت مع بت واحد محدد بالضبط. على سبيل المثال، UIAccessibilityTraitButton = 0x0000000000000001، UIAccessibilityTraitLink = 0x0000000000000002، UIAccessibilityTraitHeader = 0x0000000000000008. يتم تحقيق الدمج باستخدام OR على مستوى البت: 0x0001 | 0x0008 = 0x0009. يحلل VoiceOver القناع ويحدد السلوك.

الأنواع الرئيسية لتريتات iOS

يوفر iOS أكثر من 15 ثابتًا للتريتات. دعنا نلقي نظرة على الأنواع الرئيسية المستخدمة في 90% من السيناريوهات:

التريتالثابتسلوك VoiceOver
ButtonUIAccessibilityTraitButtonالتنشيط بنقرة مزدوجة
HeaderUIAccessibilityTraitHeaderالتنقل السريع عبر العناوين
LinkUIAccessibilityTraitLinkالتنشيط كرابط
StaticTextUIAccessibilityTraitStaticTextقراءة فقط، بدون تنشيط
SearchFieldUIAccessibilityTraitSearchFieldحقل بحث بسلوك خاص
ImageUIAccessibilityTraitImageصورة، بدون إيماءة تنشيط
SelectedUIAccessibilityTraitSelectedحالة «محدد»
PlaysSoundUIAccessibilityTraitPlaysSoundيشغل صوتًا عند التنشيط
KeyboardKeyUIAccessibilityTraitKeyboardKeyمفتاح لوحة مفاتيح
TabBarUIAccessibilityTraitTabBarعنصر شريط علامات تبويب

الثوابت متاحة في UIKit منذ iOS 3.0. iOS 14+ أضاف دعم UIAccessibilityTraits في SwiftUI عبر المعدل .accessibilityAddTraits().

تريتات نادرة ولكنها مفيدة

UIAccessibilityTraitAdjustable — للقيم القابلة للتعديل (أشرطة التمرير، المنتقيات، أشرطة تمرير مستوى الصوت). يتيح VoiceOver التمرير لأعلى/لأسفل لتغيير القيمة بخطوة محددة عبر accessibilityIncrement و accessibilityDecrement. UIAccessibilityTraitUpdatesFrequently — للعناصر ذات القيم المتغيرة بشكل متكرر (مؤقت، مؤشر تقدم). لا يقرأ VoiceOver القيمة عند كل تغيير بل يأخذ وقفة. UIAccessibilityTraitAllowsDirectInteraction — للعناصر التي يمكن للمستخدم التفاعل معها مباشرة (لوحة مفاتيح، رسم)، متجاوزًا إيماءات VoiceOver.

دمج التريتات

يمكن أن يحتوي العنصر الواحد على عدة تريتات في وقت واحد — يتم تعيين الدمج باستخدام OR على مستوى البت (|). مثال: زر محدد حاليًا — Button | Selected. سيعلن VoiceOver: «محدد. تم التصفية حسب السعر. زر.»

تعيين التريتات في الكود:

swift
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)

// أو عبر قناع:
filterButton.accessibilityTraits = [.button, .selected]

لـ UIView المخصص حيث لا يتم تعيين التريت افتراضيًا:

swift
class CustomToggle: UIControl {
    override var accessibilityTraits: UIAccessibilityTraits {
        get {
            if isOn {
                return [.button, .selected]
            } else {
                return .button
            }
        }
        set {}
    }
}

قاعدة الدمج: لا يزيد عن 3-4 تريتات لكل عنصر. التريتات المفرطة (مثل Button + Link + Header) تجعل إعلان VoiceOver طويلًا ومربكًا. وفقًا لـ Apple، «كل خاصية إضافية تزيد العبء المعرفي على المستخدم».

SwiftUI: معدّلات التريتات

في SwiftUI، يتم تعيين التريتات عبر المعدلات .accessibilityAddTraits() و .accessibilityRemoveTraits(). مثال: Text(«عنوان»).font(.largeTitle).accessibilityAddTraits(.isHeader). يضيف المعدل .isHeader UIAccessibilityTraitHeader. قائمة تريتات SwiftUI: .isButton، .isHeader، .isLink، .isSelected، .isImage، .isSearchField، .isKeyboardKey، .isStaticText، .isSummaryElement، .isToggle، .playsSound، .startsMediaSession، .updatesFrequently، .allowsDirectInteraction، .causesPageTurn، .isModal، .tabBar.

الأخطاء النموذجية عند اختيار التريت

StaticText بدلاً من Button — عنصر تحكم مخصص يبدو بصريًا كزر يحصل على تريت StaticText افتراضيًا. لا يقدم VoiceOver إيماءة تنشيط، لذلك لا يمكن للمستخدم «الضغط» على العنصر. الحل: تعيين .button بشكل صريح.

صورة بدون تريت — UIImageView مع تمكين إمكانية الوصول يحصل على تريت Image، حتى لو كان في الواقع زرًا لتكبير الصورة. قم بتعيين .button و Label «تكبير الصورة». وفقًا لـ WWDC 2023، «Deliver an Exceptional Accessibility Experience»، 40% من انتكاسات إمكانية الوصول في الإصدارات الجديدة من التطبيقات ناتجة عن عدم تطابق التريت.

Header على كل عنصر — تريت Header مخصص للعناوين الهيكلية للشاشة. إذا جعلت كل UILabel عنوانًا، فإن دوار VoiceOver في وضع «العناوين» يصبح عديم الفائدة — سيتوقف عند كل كلمة.

كيفية الإصلاح: قائمة التحقق

  • كل عنصر مخصص تفاعلي يحصل على تريت Button أو Link أو Adjustable
  • عناوين الأقسام تحصل على تريت Header (وليس StaticText)
  • أزرار الصور تحصل على تريت Button + Selected عند الحالة المحددة
  • العناصر بدون إيماءة — StaticText أو Image (قراءة فقط)

أخطاء الانحدار عند استبدال UIButton بـ UIControl

سبب شائع لفقدان التريت هو إعادة الهيكلة: مطور يستبدل UIButton بـ UIControl لعرض مخصص. UIButton تلقائيًا يحصل على تريت Button، UIControl لا. بعد إعادة الهيكلة، تحتاج إلى تعيين accessibilityTraits = .button بشكل صريح. أضف فحصًا في مراجعة الكود: «إذا استبدلت UIButton بـ UIControl — تحقق من التريت».

التريتات والحالات الديناميكية

للعنا صر ذات الحالة المتغيرة (مثل زر الإعجاب)، يجب أن يتغير التريت ديناميكيًا. في حالة «غير معجب» — Button، في حالة «معجب» — Button + Selected + Image (إذا كان هناك أيقونة). يغير VoiceOver الإعلان: «إعجاب. زر.» مقابل «محدد. إعجاب. زر.» استخدم accessibilityValue لنقل الحالة إذا كان تريت Selected غير كافٍ. ذو صلة بأزرار الاشتراك والمفضلة والمرشحات والمفاتيح.

نظير Android: role و className

في Android، لا يوجد نظير مباشر للتريتات. بدلاً من قناع البت، يتم استخدام:

  • className — قيمة AccessibilityNodeInfo.className (android.widget.Button، android.widget.TextView)
  • role — سمة XML (يتم تحديد الدور حسب نوع View)
  • stateDescription — نظير Selected: إضافة وصف للحالة (ممكّن/معطّل)

لـ View المخصصة في Android، تحتاج إلى تجاوز onInitializeAccessibilityNodeInfo:

kotlin
class CustomButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    override fun onInitializeAccessibilityNodeInfo(
        info: AccessibilityNodeInfo
    ) {
        super.onInitializeAccessibilityNodeInfo(info)
        info.className = "android.widget.Button"
        info.isClickable = true
    }
}

مطورو Flutter يجب عليهم استخدام معامل semanticsRole في عنصر واجهة Semantics: button، header، image، link، textField وغيرها. بالإضافة إلى ذلك، يتوفر semanticsLabel و semanticsHint — نظير كامل لثلاثية iOS Label + Hint + Trait.

النظائر الويب: دور WAI-ARIA

للإصدارات الويب من تطبيقات الجوال (PWA، WebView)، يتم استخدام سمة role من WAI-ARIA: role="button"، role="heading"، role="link". هذا نظير مباشر لـ accessibilityTraits. في التطبيقات الهجينة، تحقق من أن WebView ينقل أدوار ARIA إلى طبقة إمكانية الوصول الأصلية. للقيام بذلك، استخدم بروتوكول UIAccessibilityContainerDataTable في iOS أو setAccessibilityDelegate في Android. WebView مع تمكين JavaScript قد لا ينقل أدوار ARIA بشكل صحيح — اختبر بشكل منفصل.

AccessibilityNodeInfo: إجراءات إضافية

في Android، يمكنك إضافة إجراءات مخصصة إلى AccessibilityNodeInfo: AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK و ACTION_LONG_CLICK. هذا نظير تريت Button مع إيماءات إضافية. لأشرطة التمرير، استخدم ACTION_SET_PROGRESS — نظير Adjustable. لـ Spinner و DatePicker — ACTION_SET_SELECTION، ACTION_SET_DATE و ACTION_SET_TIME.

التحقق واختبار التريتات

Xcode Accessibility Inspector هو الأداة الرئيسية لـ iOS: حدد عنصرًا واعرض حقل Traits. سيظهر قائمة التريتات المعينة. دوار VoiceOver مع وضع «العناصر» يسمح بالتنقل عبر جميع عناصر التحكم في الشاشة.

اختبار آلي في Swift للتحقق من التريت:

swift
func testSubmitButtonTrait() {
    let app = XCUIApplication()
    app.launch()
    let submitButton = app.buttons["إرسال"]
    XCTAssertTrue(submitButton.isEnabled)
    // XCUIElement لا يوفر وصولًا مباشرًا إلى التريتات
    // التحقق عبر تنشيط الإيماءة
    submitButton.tap()
    XCTAssertTrue(app.staticTexts["تم إرسال النموذج"].exists)
}

التحقق اليدوي عبر VoiceOver: قم بتشغيل VoiceOver، مرر إلى العنصر، انقر مرتين — يجب أن يتم تنشيط العنصر إذا كان زرًا. إذا لم يستجب العنصر للنقر المزدوج، فإن التريت غير صحيح. استخدم إيماءة Rotor للتبديل بين الأوضاع («العناوين»، «الروابط»، «الأزرار») — كل وضع سيظهر فقط العناصر ذات التريت المقابل.

اختبار الوحدة للتريتات في iOS

قبل iOS 14، لم تكن اختبارات الوحدة تملك وصولًا مباشرًا إلى accessibilityTraits. بدءًا من iOS 14، الخاصية متاحة: XCTAssertEqual(customButton.accessibilityTraits, .button). استخدم هذا في اختبارات الوحدة للتحقق من عناصر التحكم المخصصة. يُوصى باختبار كل UIView مخصص جديد للتأكد من صحة التريت، خاصة بعد إعادة الهيكلة أو تغيير الفئة الأصلية.

الأسئلة الشائعة

كم عدد التريتات التي يمكن تعيينها لعنصر واحد؟

حتى 3-4 تريتات لكل عنصر. العدد الأكبر يجعل إعلان VoiceOver زائدًا. استخدم مجموعات: Button + Selected، Header + StaticText.

ما هو التريت الافتراضي لـ UIButton؟

UIAccessibilityTraitButton. iOS يقوم بتعيينه تلقائيًا لجميع نسخ UIButton. إذا كنت ترث من UIView وتقلد زرًا، فيجب تعيين التريت يدويًا.

هل يوجد تريت «Adjustable» وما الغرض منه؟

نعم، UIAccessibilityTraitAdjustable — للعناصر ذات القيم القابلة للتعديل (أشرطة التمرير، المنتقيات، العدادات). يسمح VoiceOver بالتمرير لأعلى/لأسفل لتغيير القيمة وقراءة الحالة الحالية.

كيفية التحقق من التريتات في SwiftUI؟

استخدم المعدل .accessibilityAddTraits(): Text(«عنوان»).font(.title).accessibilityAddTraits(.isHeader). الطريقة تعمل على iOS 14+.

ماذا يحدث إذا لم يتم تعيين تريت لعنصر تحكم مخصص؟

سيقوم VoiceOver بتعيين تريت None. العنصر لن يحصل على دور — قارئ الشاشة سيقرأ فقط Label دون الإشارة إلى النوع. المستخدم لن يعرف ما إذا كانت إيماءة التنشيط متاحة.

الخلاصة

  • Accessibility Trait — قناع بت UIAccessibilityTraits يحدد دور عنصر iOS لبرنامج VoiceOver (Button، Header، Link، StaticText وغيرها)
  • يتم دمج التريتات عبر OR على مستوى البت ([] في Swift)، لا يزيد عن 3-4 لكل عنصر
  • يجب أن تحصل UIView المخصصة على تريت صريح — افتراضيًا قد يكون None أو Image
  • في Android، يتم تعيين الدور عبر className في AccessibilityNodeInfo، في Flutter — عبر semanticsRole
  • التريت غير الصحيح (StaticText لزر) يفسد سيناريو VoiceOver: لا توجد إيماءة تنشيط
  • تحقق من التريتات عبر Accessibility Inspector في Xcode ودوار VoiceOver
  • في SwiftUI، استخدم .accessibilityAddTraits() لتكوين التريتات بشكل تصريحي

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا