Accessibility Label 是界面元素的名称,VoiceOver(iOS)或 TalkBack(Android)在聚焦时会念出它。在 iOS 中,该属性称为 accessibilityLabel,在 Android 中则称为 contentDescription,用于不包含文本的元素。根据 Apple Developer Documentation, 2024,标签是无障碍的基础:没有它,用户无法识别元素。标签在屏幕内必须是唯一的,并以易于理解的语言反映元素的本质。
要点
Accessibility Label是一个字符串属性,用于为辅助技术定义元素的名称。当用户开启 VoiceOver 并用手指在屏幕上滑动时,屏幕读取器会读出聚焦所在元素的 Label。没有标签,用户只能听到元素的类型:“按钮”、“图像”——而不知道其用途。
根据 Google I/O 2024「Accessibility Testing」,商店应用程序中 35% 的严重无障碍违反与 Label 缺失或不正确有关。Android 上的 Accessibility Scanner 将标签缺失检测为最严重级别的错误。原则性限制:Label 不应包含元素类型。VoiceOver 和 TalkBack 会自动在声明中添加角色(按钮、标题、链接)。如果 Label 包含“发送按钮”,用户将听到:“发送按钮,按钮”——重复。
WCAG 4.1.2(A 级)要求用户界面中的每个元素都具有可程序确定的名称(name)、角色(role)和值(value)。Accessibility Label 提供名称。如果 Label 缺失,则该条目被认为违反,应用程序无法通过基本认证。
在 iOS 中,accessibilityLabel被所有 UIView 从 UIAccessibility 协议继承。如果元素包含文本(带 title 的 UIButton、带 text 的 UILabel),Label 会自动设置为该文本。对于 UIImageView、自定义控件和容器,需要手动设置 Label。
自定义表格单元格的示例:
class CustomTableViewCell: UITableViewCell {
let titleLabel = UILabel()
let priceLabel = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
self.isAccessibilityElement = true
self.accessibilityLabel =
"\(titleLabel.text ?? "") - \(priceLabel.text ?? "")"
}
}
对于自定义 UIView,可以覆写 accessibilityLabel 的 getter:
class RatingView: UIView {
var rating: Int = 5
override var accessibilityLabel: String? {
get { return "评分:\(rating) / 5" }
set {}
}
}
Apple HIG, 2024 建议:如果元素由多个子元素组成(例如带有名称和价格的产品卡片),请将它们组合成一个具有复合 Label 的无障碍元素。在父元素上设置 isAccessibilityElement = true,在子元素上设置 false。
如果 UILabel 使用 NSAttributedString,accessibilityLabel 默认等于 .string(纯文本)。如果需要传递语义上不同的值(例如,图标符号应读作“星星”而非符号 ★),请显式设置 accessibilityLabel。VoiceOver 无法有意义地读取 Unicode 符号。
在 Android 中,contentDescription担任 ImageView、ImageButton 和自定义 View 的 Label。对于内置文本的 TextView 和 Button,无需设置 contentDescription——TalkBack 会自动读取文本。
通过 Kotlin 进行编程设置:
binding.iconStar.contentDescription = "商品在收藏夹中"
// 对于具有多个元素的自定义视图
binding.customCard.setContentDescription(
"\(title) 金额 \(price)")
在 XML 中用于装饰性元素:
<ImageView
android:contentDescription="@null"
android:src="@drawable/divider"
android:importantForAccessibility="no" />
importantForAccessibility = "no"属性完全将元素从无障碍树中排除。在 iOS 中,它的等效属性是 isAccessibilityElement = false。
在 Jetpack Compose 中,Label 通过semantics修饰符设置:
Image(
painter = painterResource(R.drawable.ic_search),
contentDescription = "商品搜索",
modifier = Modifier.semantics {
contentDescription = "商品搜索"
}
)
在 Compose 中,contentDescription 是 Image 的必须参数——没有它,代码将无法编译(警告)。这通过 API 设计强制提升了无障碍。
Accessibility Label回答“这是什么元素?”的问题。Hint(iOS 中的 accessibilityHint,Android 中 contentDescription 中的附加文本)——“交互时会发生什么?”。VoiceOver 会顺序念出它们:先 Label,后 Hint。
删除按钮的示例:
根据 Deque University, 2024,Label 和 Hint 的正确分离使 VoiceOver 用户的任务完成率提高了 28%。有认知障碍的用户尤其依赖 Hint:如果没有说明就冒险按下“删除”,40%的用户会放弃操作。
常见错误:在 Label 中写“删除按钮”而非“删除”。元素类型(按钮)由 VoiceOver 通过 trait 自动添加。结果,用户听到:“删除按钮,按钮”——重复。正确的 Label:“删除”,Hint:“将删除所选照片”
标签的本地化是必须的——通过标准机制实现:iOS 中的 NSLocalizedString,Android 中的 @string/ 字符串资源。切勿在没有本地化的情况下用英语拼接方式设置 Label。
基于 W3C WCAG 2.2 的良好 Label 规则:
在应用程序中为 Label 使用统一的词汇表。如果一个屏幕上写着“收藏”,而另一个屏幕上写着“书签”,用户就会困惑。创建一个无障碍术语表——与设计师和本地化人员协调。
对于输入字段(UITextField、EditText),Label 应与填充文本或字段标题一致。但是填充文本在输入文本后常常会消失。使用 accessibilityLabel 作为永久名称,使用 accessibilityValue 作为字段当前内容——这是 WCAG 4.1.2 标准。解决方案:静态设置 accessibilityLabel(等于字段标题),动态设置 accessibilityValue(等于输入的文本)。在 iOS 中这是自动的,但对于自定义字段——需要通过覆写 accessibilityValue 手动实现。检查 VoiceOver 是否读取“电子邮件,example@domain.com,文本字段”而非“,文本字段”。
自动化测试是保证 Label 在所有屏幕上正确性的唯一方法。iOS 提供了 XCUIApplication,可以访问 .label,Android 则提供 AccessibilityCheckRule 和 setContentDescription。
iOS 测试示例:
func testLabelsAreUnique() {
let app = XCUIApplication()
app.launch()
let allButtons = app.buttons.allElementsBoundByIndex
let labels = allButtons.compactMap { $0.label }
let uniqueLabels = Set(labels)
XCTAssertEqual(labels.count, uniqueLabels.count,
"发现重复的 Label")
}
使用 Espresso 的 Android 测试示例:
@Test
fun testButtonHasAccessibilityLabel() {
onView(withId(R.id.btnSubmit))
.check(matches(
withContentDescription(containsString("发送"))
))
}
手动测试:开启 VoiceOver(iOS)或 TalkBack(Android),然后用手指向右滑动遍历屏幕上的所有元素。每个元素应收到有意义的声明。如果只听到“按钮”或“图像”——Label 缺失。
设置 Label 后,VoiceOver 用户可以使用转盘进行快速导航:“按钮”、“标题”、“链接”等模式。如果 Label 设置正确,VoiceOver 将元素包含在相应的转盘模式中。检查所有按钮是否在“按钮”模式中可见,所有标题是否在“标题”模式中可见。
Label 还影响 VoiceOver 的搜索功能。用户可以在搜索模式中输入词语,VoiceOver 将把聚焦移到具有匹配 Label 的元素上。因此,Label 应包含用户查找元素时使用的关键词。
将 Label 检查添加到管道。在 iOS 上,使用带 fastlane scan 的XCUITest。在 Android 上,使用Accessibility Test Framework,其 AccessibilityCheckRule 规则可检测空的 contentDescription。这可以避免在合并新屏幕时产生回退。
常见问题
Label 标识元素(“搜索”),Hint 解释操作的结果(“将打开搜索屏幕”)。VoiceOver 在聚焦时立即念出 Label,而 Hint 在详细描述模式下念出。
在 iOS 中,UILabel会自动获取与其文本相同的 accessibilityLabel。无需额外设置。在 Android 中,TextView 的行为类似。
在父 View 上设置isAccessibilityElement = true,并覆写 accessibilityLabel,返回从子元素拼接的文本。对于复杂组件,使用分隔符进行拼接。
为重复元素添加上下文:“购买 iPhone 15”、“购买 iPhone 15 Pro”。通过 UI 测试自动化检查——收集所有 Label 并检查无重复。
不可以。要隐藏元素,请在 iOS 中使用isAccessibilityElement = false,或在 Android 中使用 importantForAccessibility = "no"。空 Label 不会隐藏元素——屏幕读取器将读取“无名称”。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。