Accessibility Trait — ویژگیای از عنصر iOS است که نقش و رفتار آن را برای VoiceOver تعیین میکند. ترِیت به صفحهخوان میگوید که عنصر چگونه باید خوانده شود و چه ژستهایی در دسترس هستند: آیا دکمه، عنوان، پیوند یا فیلد جستجو است. طبق Apple UIAccessibilityTraits، 2024، سیستم از ۱۵+ ثابت پشتیبانی میکند که میتوان با ماسک بیتی ترکیب کرد. ترِیت به درستی انتخاب شده تا ۵۰٪ زمان ناوبری را برای کاربران VoiceOver کاهش میدهد.
نکات کلیدی
Accessibility Trait — پرچمی است که روی عنصر UIView برای نشان دادن نقش معنایی آن برای VoiceOver تنظیم میشود. ترِیت یکی از سه مؤلفه سهگانه accessibility اپل است: Label (نام), Hint (توضیح), Trait (نقش). iOS از ماسک بیتی UIAccessibilityTraits (UInt64) استفاده میکند که در آن هر بیت مربوط به یک نقش خاص است. VoiceOver نقش را پس از Label و Hint میخواند: «دکمه ارسال. فرم را باز میکند» — «دکمه» به لطف ترِیت UIAccessibilityTraitButton اضافه شده است.
به طور پیشفرض UIButton UIAccessibilityTraitButton، UILabel — UIAccessibilityTraitStaticText، UIImageView — UIAccessibilityTraitImage دریافت میکند. هنگام استفاده از کنترلهای سفارشی، توسعهدهنده موظف است ترِیت را به صورت دستی تنظیم کند. Apple Human Interface Guidelines، 2024، این را «یکی از بحرانیترین مراحل در تضمین accessibility» مینامد.
بدون ترِیت مناسب، کاربر نمیداند از کدام ژست استفاده کند: ضربه تکی (فعالسازی دکمه), ضربه دوبل (بزرگنمایی) یا ژست کشیدن (سوئیچ). ترِیت تعیین میکند که VoiceOver کدام ژستها را روی عنصر فعال کند.
UIAccessibilityTraits — typealias UInt64 است. هر ترِیت یک ثابت است که دقیقاً یک بیت در آن تنظیم شده است. مثلاً UIAccessibilityTraitButton = 0x0000000000000001، UIAccessibilityTraitLink = 0x0000000000000002، UIAccessibilityTraitHeader = 0x0000000000000008. ترکیب با OR بیتی به دست میآید: 0x0001 | 0x0008 = 0x0009. VoiceOver ماسک را تحلیل کرده و رفتار را تعیین میکند.
iOS بیش از ۱۵ ثابت ترِیت ارائه میدهد. بیایید اصلیترینهایی که در ۹۰٪ سناریوها استفاده میشوند را بررسی کنیم:
| تریت | ثابت | رفتار 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 {}
}
}
قانون ترکیب: بیش از ۳-۴ ترِیت برای هر عنصر نباشد. ترِیتهای اضافی (مثلاً Button + Link + Header) اعلام VoiceOver را بیش از حد طولانی و گیجکننده میکند. به گفته اپل، «هر ویژگی اضافی بار شناختی کاربر را افزایش میدهد».
در 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 را تنظیم کنید.
Image بدون ترِیت — UIImageView با accessibility فعال، ترِیت Image دریافت میکند، حتی اگر در واقع دکمه بزرگنمایی عکس باشد. .button و Label «بزرگنمایی عکس» را تنظیم کنید. طبق WWDC 2023، «Deliver an Exceptional Accessibility Experience»، ۴۰٪ از رگرسیونهای accessibility در نسخههای جدید برنامهها دقیقاً به دلیل عدم تطابق ترِیت ایجاد میشود.
Header روی هر عنصر — ترِیت Header برای عناوین ساختاری صفحه طراحی شده است. اگر هر UILabel را عنوان کنید، روتور VoiceOver در حالت «عناوین» بیفایده میشود — روی هر کلمه توقف میکند.
علت رایج از دست دادن ترِیت — بازآفرینی: توسعهدهنده UIButton را برای نمایش سفارشی با UIControl جایگزین میکند. UIButton به طور خودکار ترِیت Button دریافت میکند، UIControl — دریافت نمیکند. پس از بازآفرینی باید به صراحت accessibilityTraits = .button تنظیم شود. یک بررسی به کد-ریویو اضافه کنید: «اگر UIButton با UIControl جایگزین شد — ترِیت را بررسی کنید».
برای عناصر با حالت متغیر (مثلاً دکمه لایک) ترِیت باید به صورت پویا تغییر کند. در حالت «لایک نشده» — Button، در حالت «لایک شده» — Button + Selected + Image (اگر آیکون باشد). VoiceOver اعلام را تغییر میدهد: «پسندیدن. دکمه» در مقابل «انتخاب شده. پسندیدن. دکمه». اگر ترِیت Selected کافی نیست، از accessibilityValue برای انتقال حالت استفاده کنید. برای دکمههای اشتراک، موارد دلخواه، فیلترها و سوئیچها کاربرد دارد.
در 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 را به لایه accessibility بومی منتقل میکند. برای این کار از پروتکل 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 را روشن کنید، انگشت خود را به عنصر ببرید، دو بار ضربه بزنید — عنصر باید فعال شود، اگر Button باشد. اگر عنصر به ضربه دوبل واکنش نشان ندهد، ترِیت نادرست است. از ژست Rotor برای جابجایی بین حالتها استفاده کنید («عناوین», «پیوندها», «دکمهها») — هر حالت فقط عناصر با ترِیت مربوطه را نشان میدهد.
قبل از iOS 14 تستهای واحد دسترسی مستقیم به accessibilityTraits نداشتند. از iOS 14 به بعد ویژگی در دسترس است: XCTAssertEqual(customButton.accessibilityTraits, .button). این را در تستهای ماژولار برای بررسی کنترلهای سفارشی استفاده کنید. توصیه میشود هر UIView سفارشی جدید را از نظر صحت ترِیت، به ویژه پس از بازآفرینی یا تغییر کلاس والد، آزمایش کنید.
سؤالات متداول
حداکثر ۳-۴ ترِیت برای هر عنصر. تعداد بیشتر باعث میشود اعلام VoiceOut اضافی باشد. از ترکیبها استفاده کنید: Button + Selected، Header + StaticText.
UIAccessibilityTraitButton. iOS به طور خودکار آن را برای همه نمونههای UIButton تنظیم میکند. اگر از UIView ارثبری میکنید و دکمه را شبیهسازی میکنید، ترِیت باید به صورت دستی تنظیم شود.
بله، UIAccessibilityTraitAdjustable — برای عناصر با مقدار قابل تنظیم (لغزندهها، انتخابگرها، شمارندهها). VoiceOver امکان کشیدن به بالا/پایین برای تغییر مقدار را فراهم میکند و وضعیت فعلی را میخواند.
از اصلاحکننده .accessibilityAddTraits() استفاده کنید: Text("عنوان").font(.title).accessibilityAddTraits(.isHeader). این متد در iOS 14+ کار میکند.
VoiceOver ترِیت None را اختصاص میدهد. عنصر نقشی دریافت نمیکند — صفحهخوان فقط Label را بدون مشخص کردن نوع میخواند. کاربر نمیداند آیا ژست فعالسازی در دسترس است یا خیر.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید