Accessibility Trait: ماهیت، انواع و نحوه کار در توسعه

نویسنده: IT Sectr منتشر شده: 2026-05-16 زمان مطالعه: 9 دقیقه

Accessibility Trait — ویژگی‌ای از عنصر iOS است که نقش و رفتار آن را برای VoiceOver تعیین می‌کند. ترِیت به صفحه‌خوان می‌گوید که عنصر چگونه باید خوانده شود و چه ژست‌هایی در دسترس هستند: آیا دکمه، عنوان، پیوند یا فیلد جستجو است. طبق Apple UIAccessibilityTraits، 2024، سیستم از ۱۵+ ثابت پشتیبانی می‌کند که می‌توان با ماسک بیتی ترکیب کرد. ترِیت به درستی انتخاب شده تا ۵۰٪ زمان ناوبری را برای کاربران VoiceOver کاهش می‌دهد.

نکات کلیدی

  • Accessibility Trait — نقش عنصر iOS برای VoiceOver؛ از طریق ثابت‌های UIAccessibilityTraits تنظیم می‌شود
  • ترِیت‌ها را می‌توان با عملگر | برای ایجاد نقش‌های پیچیده ترکیب کرد (دکمه + انتخاب شده)
  • هر عنصر می‌تواند همزمان چندین ترِیت داشته باشد، اما برای جلوگیری از سردرگمی حداکثر ۳-۴ عدد
  • ترِیت اشتباه (مثلاً StaticText برای دکمه) سناریوی تعامل را خراب می‌کند: کاربر نمی‌داند آیا ژست در دسترس است یا خیر
  • در Android معادل آن ویژگی‌های role و className در AccessibilityNodeInfo است

Accessibility Trait چیست

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

UIAccessibilityTraits — typealias UInt64 است. هر ترِیت یک ثابت است که دقیقاً یک بیت در آن تنظیم شده است. مثلاً UIAccessibilityTraitButton = 0x0000000000000001، UIAccessibilityTraitLink = 0x0000000000000002، UIAccessibilityTraitHeader = 0x0000000000000008. ترکیب با OR بیتی به دست می‌آید: 0x0001 | 0x0008 = 0x0009. VoiceOver ماسک را تحلیل کرده و رفتار را تعیین می‌کند.

انواع اصلی ترِیت‌های iOS

iOS بیش از ۱۵ ثابت ترِیت ارائه می‌دهد. بیایید اصلی‌ترین‌هایی که در ۹۰٪ سناریوها استفاده می‌شوند را بررسی کنیم:

تریتثابترفتار 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 {}
    }
}

قانون ترکیب: بیش از ۳-۴ ترِیت برای هر عنصر نباشد. ترِیت‌های اضافی (مثلاً Button + Link + Header) اعلام VoiceOver را بیش از حد طولانی و گیج‌کننده می‌کند. به گفته اپل، «هر ویژگی اضافی بار شناختی کاربر را افزایش می‌دهد».

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 را تنظیم کنید.

Image بدون ترِیت — UIImageView با accessibility فعال، ترِیت Image دریافت می‌کند، حتی اگر در واقع دکمه بزرگنمایی عکس باشد. .button و Label «بزرگنمایی عکس» را تنظیم کنید. طبق WWDC 2023، «Deliver an Exceptional Accessibility Experience»، ۴۰٪ از رگرسیون‌های accessibility در نسخه‌های جدید برنامه‌ها دقیقاً به دلیل عدم تطابق ترِیت ایجاد می‌شود.

Header روی هر عنصر — ترِیت Header برای عناوین ساختاری صفحه طراحی شده است. اگر هر UILabel را عنوان کنید، روتور VoiceOver در حالت «عناوین» بی‌فایده می‌شود — روی هر کلمه توقف می‌کند.

چگونه رفع کنیم: چک‌لیست

  • هر عنصر سفارشی تعاملی ترِیت Button، Link یا Adjustable دریافت می‌کند
  • عناوین بخش‌ها ترِیت Header دریافت می‌کنند (نه StaticText)
  • تصاویر-دکمه‌ها در حالت selected ترِیت Button + Selected دریافت می‌کنند
  • عناصر بدون ژست — StaticText یا Image (فقط خواندنی)

باگ‌های رگرسیون هنگام تغییر UIButton به UIControl

علت رایج از دست دادن ترِیت — بازآفرینی: توسعه‌دهنده UIButton را برای نمایش سفارشی با UIControl جایگزین می‌کند. UIButton به طور خودکار ترِیت Button دریافت می‌کند، UIControl — دریافت نمی‌کند. پس از بازآفرینی باید به صراحت accessibilityTraits = .button تنظیم شود. یک بررسی به کد-ریویو اضافه کنید: «اگر UIButton با UIControl جایگزین شد — ترِیت را بررسی کنید».

تریت‌ها و حالت‌های پویا

برای عناصر با حالت متغیر (مثلاً دکمه لایک) ترِیت باید به صورت پویا تغییر کند. در حالت «لایک نشده» — Button، در حالت «لایک شده» — Button + Selected + Image (اگر آیکون باشد). VoiceOver اعلام را تغییر می‌دهد: «پسندیدن. دکمه» در مقابل «انتخاب شده. پسندیدن. دکمه». اگر ترِیت Selected کافی نیست، از accessibilityValue برای انتقال حالت استفاده کنید. برای دکمه‌های اشتراک، موارد دلخواه، فیلترها و سوئیچ‌ها کاربرد دارد.

معادل 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 را به لایه accessibility بومی منتقل می‌کند. برای این کار از پروتکل 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 را روشن کنید، انگشت خود را به عنصر ببرید، دو بار ضربه بزنید — عنصر باید فعال شود، اگر Button باشد. اگر عنصر به ضربه دوبل واکنش نشان ندهد، ترِیت نادرست است. از ژست Rotor برای جابجایی بین حالت‌ها استفاده کنید («عناوین», «پیوندها», «دکمه‌ها») — هر حالت فقط عناصر با ترِیت مربوطه را نشان می‌دهد.

تست واحد ترِیت‌ها در iOS

قبل از iOS 14 تست‌های واحد دسترسی مستقیم به accessibilityTraits نداشتند. از iOS 14 به بعد ویژگی در دسترس است: XCTAssertEqual(customButton.accessibilityTraits, .button). این را در تست‌های ماژولار برای بررسی کنترل‌های سفارشی استفاده کنید. توصیه می‌شود هر UIView سفارشی جدید را از نظر صحت ترِیت، به ویژه پس از بازآفرینی یا تغییر کلاس والد، آزمایش کنید.

سؤالات متداول

چند ترِیت می‌توان برای یک عنصر تنظیم کرد؟

حداکثر ۳-۴ ترِیت برای هر عنصر. تعداد بیشتر باعث می‌شود اعلام VoiceOut اضافی باشد. از ترکیب‌ها استفاده کنید: 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) ترکیب می‌شوند، حداکثر ۳-۴ برای هر عنصر
  • UIViewهای سفارشی باید تریت صریح دریافت کنند — به طور پیش‌فرض می‌تواند None یا Image باشد
  • در Android نقش از طریق className در AccessibilityNodeInfo، در Flutter از طریق semanticsRole تعیین می‌شود
  • تریت اشتباه (StaticText برای دکمه) سناریوی VoiceOver را خراب می‌کند: بدون ژست فعال‌سازی
  • تریت‌ها را از طریق Accessibility Inspector در Xcode و روتور VoiceOver بررسی کنید
  • در SwiftUI از .accessibilityAddTraits() برای تنظیم اعلانی ترِیت‌ها استفاده کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید