Accessibility Trait:本质、有哪些类型以及在开发中如何工作

作者: IT Sectr 发布日期: 2026-05-16 阅读时间: 9 分钟

Accessibility Trait 是 iOS 元素的一个属性,它决定了该元素在 VoiceOver 中的角色和行为。特性告诉屏幕阅读器元素应该如何被朗读以及哪些手势可用:它是按钮、标题、链接还是搜索字段。根据 Apple UIAccessibilityTraits,2024,系统支持 15 个以上的常量,可以通过位掩码组合。正确选择的特性可为 VoiceOver 用户节省多达 50% 的导航时间。

要点

  • Accessibility Trait — iOS 元素在 VoiceOver 中的角色;通过 UIAccessibilityTraits 常量设置
  • 特性可以通过 | 运算符组合以创建复杂角色(按钮 + 已选定)
  • 每个元素可以同时拥有多个特性,但为避免混淆,不超过 3-4 个
  • 错误的特性(例如为按钮设置 StaticText)会破坏交互场景:用户不知道手势是否可用
  • 在 Android 中,对应的是 AccessibilityNodeInfo 中的 role 和 className 属性

什么是 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。组合通过按位或实现: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+ 中,通过 .accessibilityAddTraits() 修饰符在 SwiftUI 中添加了对 UIAccessibilityTraits 的支持。

罕见但有用的特性

UIAccessibilityTraitAdjustable — 用于可调整的值(滑块、选择器、音量滑块)。VoiceOver 允许向上/向下滑动以通过 accessibilityIncrement 和 accessibilityDecrement 定义的步长更改值。UIAccessibilityTraitUpdatesFrequently — 用于值频繁变化的元素(计时器、加载指示器)。VoiceOver 不会在每次更改时读取值,而是暂停。UIAccessibilityTraitAllowsDirectInteraction — 用于用户可以直接与之交互的元素(键盘、绘图工具),绕过 VoiceOver 手势。

组合特性

一个元素可以同时拥有多个特性 — 组合通过按位或(|)指定。例如:当前已选定的按钮 — 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。

无特性的 Image — 启用了无障碍的 UIImageView 会获得 Image 特性,即使它实际上是用于放大照片的按钮。分配 .button 和 “放大照片” 标签。根据 WWDC 2023,“Deliver an Exceptional Accessibility Experience”,应用程序新版本中 40% 的无障碍回归正是由特性不匹配引起的。

每个元素上都用 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 的对应:添加状态描述(启用/禁用)

对于 Android 中的自定义 View,需要重写 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 开发人员应在 Semantics 小部件中使用 semanticsRole 参数:button、header、image、link、textField 等。此外,还有 semanticsLabelsemanticsHint — iOS 三元组 Label + Hint + Trait 的完整对应。

Web 对应:WAI-ARIA 角色

对于移动应用的 Web 版本(PWA、WebView),使用 WAI-ARIA 的 role 属性:role="button"、role="heading"、role="link"。这是 accessibilityTraits 的直接对应。在混合应用中,检查 WebView 是否将 ARIA 角色传递到原生无障碍层。为此,在 iOS 中使用 UIAccessibilityContainerDataTable 协议,在 Android 中使用 setAccessibilityDelegate。启用 JavaScript 的 WebView 可能无法正确传递 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 的特性正确性,尤其是在重构或更改父类之后。

常见问题解答

一个元素可以设置多少个特性?

每个元素最多 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 等)
  • 特性通过按位或(Swift 中的 [])组合,每个元素最多 3-4 个
  • 自定义 UIView 必须获得显式特性 — 默认情况下可能是 None 或 Image
  • 在 Android 中,角色通过 AccessibilityNodeInfo 中的 className 设置,在 Flutter 中通过 semanticsRole 设置
  • 错误的特性(为按钮设置 StaticText)会破坏 VoiceOver 场景:没有激活手势
  • 通过 Xcode 中的 Accessibility Inspector 和 VoiceOver 转子检查特性
  • 在 SwiftUI 中使用 .accessibilityAddTraits() 以声明方式设置特性

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读