Accessibility Trait هي خاصية لعنصر iOS تحدد دوره وسلوكه لبرنامج VoiceOver. يخبر التريت قارئ الشاشة كيف يجب نطق العنصر وما هي الإيماءات المتاحة: هل هو زر أم عنوان أم رابط أم حقل بحث. وفقًا لـ Apple UIAccessibilityTraits، 2024، يدعم النظام أكثر من 15 ثابتًا يمكن دمجها باستخدام قناع بت. التريت المختار بشكل صحيح يوفر ما يصل إلى 50% من وقت التنقل لمستخدمي VoiceOver.
النقاط الرئيسية
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 هو typealias UInt64. كل تريت هو ثابت مع بت واحد محدد بالضبط. على سبيل المثال، UIAccessibilityTraitButton = 0x0000000000000001، UIAccessibilityTraitLink = 0x0000000000000002، UIAccessibilityTraitHeader = 0x0000000000000008. يتم تحقيق الدمج باستخدام OR على مستوى البت: 0x0001 | 0x0008 = 0x0009. يحلل VoiceOver القناع ويحدد السلوك.
يوفر iOS أكثر من 15 ثابتًا للتريتات. دعنا نلقي نظرة على الأنواع الرئيسية المستخدمة في 90% من السيناريوهات:
| التريت | الثابت | سلوك VoiceOver |
|---|---|---|
| Button | UIAccessibilityTraitButton | التنشيط بنقرة مزدوجة |
| Header | UIAccessibilityTraitHeader | التنقل السريع عبر العناوين |
| Link | UIAccessibilityTraitLink | التنشيط كرابط |
| StaticText | UIAccessibilityTraitStaticText | قراءة فقط، بدون تنشيط |
| SearchField | UIAccessibilityTraitSearchField | حقل بحث بسلوك خاص |
| Image | UIAccessibilityTraitImage | صورة، بدون إيماءة تنشيط |
| Selected | UIAccessibilityTraitSelected | حالة «محدد» |
| PlaysSound | UIAccessibilityTraitPlaysSound | يشغل صوتًا عند التنشيط |
| KeyboardKey | UIAccessibilityTraitKeyboardKey | مفتاح لوحة مفاتيح |
| TabBar | UIAccessibilityTraitTabBar | عنصر شريط علامات تبويب |
الثوابت متاحة في UIKit منذ iOS 3.0. iOS 14+ أضاف دعم UIAccessibilityTraits في SwiftUI عبر المعدل .accessibilityAddTraits().
UIAccessibilityTraitAdjustable — للقيم القابلة للتعديل (أشرطة التمرير، المنتقيات، أشرطة تمرير مستوى الصوت). يتيح VoiceOver التمرير لأعلى/لأسفل لتغيير القيمة بخطوة محددة عبر accessibilityIncrement و accessibilityDecrement. UIAccessibilityTraitUpdatesFrequently — للعناصر ذات القيم المتغيرة بشكل متكرر (مؤقت، مؤشر تقدم). لا يقرأ VoiceOver القيمة عند كل تغيير بل يأخذ وقفة. UIAccessibilityTraitAllowsDirectInteraction — للعناصر التي يمكن للمستخدم التفاعل معها مباشرة (لوحة مفاتيح، رسم)، متجاوزًا إيماءات VoiceOver.
يمكن أن يحتوي العنصر الواحد على عدة تريتات في وقت واحد — يتم تعيين الدمج باستخدام OR على مستوى البت (|). مثال: زر محدد حاليًا — Button | Selected. سيعلن VoiceOver: «محدد. تم التصفية حسب السعر. زر.»
تعيين التريتات في الكود:
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)
// أو عبر قناع:
filterButton.accessibilityTraits = [.button, .selected]
لـ UIView المخصص حيث لا يتم تعيين التريت افتراضيًا:
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، يتم تعيين التريتات عبر المعدلات .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 في وضع «العناوين» يصبح عديم الفائدة — سيتوقف عند كل كلمة.
سبب شائع لفقدان التريت هو إعادة الهيكلة: مطور يستبدل UIButton بـ UIControl لعرض مخصص. UIButton تلقائيًا يحصل على تريت Button، UIControl لا. بعد إعادة الهيكلة، تحتاج إلى تعيين accessibilityTraits = .button بشكل صريح. أضف فحصًا في مراجعة الكود: «إذا استبدلت UIButton بـ UIControl — تحقق من التريت».
للعنا صر ذات الحالة المتغيرة (مثل زر الإعجاب)، يجب أن يتغير التريت ديناميكيًا. في حالة «غير معجب» — Button، في حالة «معجب» — Button + Selected + Image (إذا كان هناك أيقونة). يغير VoiceOver الإعلان: «إعجاب. زر.» مقابل «محدد. إعجاب. زر.» استخدم accessibilityValue لنقل الحالة إذا كان تريت Selected غير كافٍ. ذو صلة بأزرار الاشتراك والمفضلة والمرشحات والمفاتيح.
في Android، لا يوجد نظير مباشر للتريتات. بدلاً من قناع البت، يتم استخدام:
لـ View المخصصة في Android، تحتاج إلى تجاوز onInitializeAccessibilityNodeInfo:
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.
للإصدارات الويب من تطبيقات الجوال (PWA، WebView)، يتم استخدام سمة role من WAI-ARIA: role="button"، role="heading"، role="link". هذا نظير مباشر لـ accessibilityTraits. في التطبيقات الهجينة، تحقق من أن WebView ينقل أدوار ARIA إلى طبقة إمكانية الوصول الأصلية. للقيام بذلك، استخدم بروتوكول UIAccessibilityContainerDataTable في iOS أو setAccessibilityDelegate في Android. WebView مع تمكين JavaScript قد لا ينقل أدوار ARIA بشكل صحيح — اختبر بشكل منفصل.
في 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 للتحقق من التريت:
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 14، لم تكن اختبارات الوحدة تملك وصولًا مباشرًا إلى accessibilityTraits. بدءًا من iOS 14، الخاصية متاحة: XCTAssertEqual(customButton.accessibilityTraits, .button). استخدم هذا في اختبارات الوحدة للتحقق من عناصر التحكم المخصصة. يُوصى باختبار كل UIView مخصص جديد للتأكد من صحة التريت، خاصة بعد إعادة الهيكلة أو تغيير الفئة الأصلية.
الأسئلة الشائعة
حتى 3-4 تريتات لكل عنصر. العدد الأكبر يجعل إعلان VoiceOver زائدًا. استخدم مجموعات: Button + Selected، Header + StaticText.
UIAccessibilityTraitButton. iOS يقوم بتعيينه تلقائيًا لجميع نسخ UIButton. إذا كنت ترث من UIView وتقلد زرًا، فيجب تعيين التريت يدويًا.
نعم، UIAccessibilityTraitAdjustable — للعناصر ذات القيم القابلة للتعديل (أشرطة التمرير، المنتقيات، العدادات). يسمح VoiceOver بالتمرير لأعلى/لأسفل لتغيير القيمة وقراءة الحالة الحالية.
استخدم المعدل .accessibilityAddTraits(): Text(«عنوان»).font(.title).accessibilityAddTraits(.isHeader). الطريقة تعمل على iOS 14+.
سيقوم VoiceOver بتعيين تريت None. العنصر لن يحصل على دور — قارئ الشاشة سيقرأ فقط Label دون الإشارة إلى النوع. المستخدم لن يعرف ما إذا كانت إيماءة التنشيط متاحة.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا