iOS UIKit:如何让元素仅对自动化暴露而非无障碍访问?
无障碍与自动化测试配置问题
现有代码实现
@IBOutlet weak var dataDisclosureView: UIStackView! // Main ContainerView @IBOutlet private weak var titleLabel: UILabel! { didSet { titleLabel.text = "Hello" } } @IBOutlet private weak var descriptionLabel: UILabel! { didSet { descriptionLabel.text = "World" } } @IBOutlet weak var descriptionView: UIStackView! { // sub container view containing titleLabel and descriptionLabel didSet { descriptionView.isAccessibilityElement = true descriptionView.accessibilityLabel = "Hello" descriptionView.accessibilityIdentifier = "test_hello" } } @IBOutlet private weak var requestButton: UIButton! { didSet { requestButton.isAccessibilityElement = true requestButton.accessibilityLabel = "Request Button" requestButton.accessibilityIdentifier = "test_button" } } override func viewDidLoad() { super.viewDidLoad() dataDisclosureView.isAccessibilityElement = false dataDisclosureView.accessibilityElements = [ descriptionView ?? "" ] if #available(iOS 17.0, *) { dataDisclosureView.automationElements = [ descriptionView ?? "", requestButton ?? ""] } else { // Fallback on earlier versions } let requestButtonAction = UIAccessibilityCustomAction(name: "start", target: self, selector: #selector( request)) dataDisclosureView.accessibilityCustomActions = [ requestButtonAction ] }
需求与问题
需求
- 为
descriptionLabel、titleLabel、requestButton和hintLabel设置accessibilityIdentifier,支持自动化测试 - 为
descriptionView和requestButton设置accessibilityLabel,供VoiceOver无障碍访问
问题
Accessibility Inspector中无法看到Button、TitleLabel及descriptionLabel的accessibilityIdentifier
已尝试的可行方案(不符合WWDC思路)
dataDisclosureView.accessibilityElements = [dataDisclosureView as Any, titleLabel as Any, descriptionLabel as Any, requestButton as Any, hintLabel as Any] if #available(iOS 17.0, *) { dataDisclosureView.automationElements = [titleLabel as Any, descriptionLabel as Any, requestButton as Any, hintLabel as Any] } else { // Fallback on earlier versions }
符合WWDC思路的正确实现
按照WWDC提出的规则:
- 元素无需被VoiceOver识别 → 不加入
accessibilityElements - 元素仅需供自动化测试使用 → 仅加入
automationElements(iOS17+)
步骤1:为所有需要自动化的元素设置accessibilityIdentifier
先在各元素的didSet中补充accessibilityIdentifier配置:
@IBOutlet private weak var titleLabel: UILabel! { didSet { titleLabel.text = "Hello" titleLabel.accessibilityIdentifier = "test_title" // 新增 } } @IBOutlet private weak var descriptionLabel: UILabel! { didSet { descriptionLabel.text = "World" descriptionLabel.accessibilityIdentifier = "test_description" // 新增 } } // 假设hintLabel的IBOutlet配置如下 @IBOutlet private weak var hintLabel: UILabel! { didSet { hintLabel.accessibilityIdentifier = "test_hint" // 新增 } }
步骤2:修正容器视图的无障碍与自动化配置
override func viewDidLoad() { super.viewDidLoad() // 主容器不作为独立无障碍元素 dataDisclosureView.isAccessibilityElement = false // VoiceOver需要识别的元素:descriptionView、requestButton dataDisclosureView.accessibilityElements = [descriptionView, requestButton].compactMap { $0 } // iOS17+ 自动化专用元素:仅需自动化识别的titleLabel、descriptionLabel、hintLabel,可包含VoiceOver元素(自动化也能识别) if #available(iOS 17.0, *) { dataDisclosureView.automationElements = [ titleLabel, descriptionLabel, requestButton, hintLabel ].compactMap { $0 } } // 保留自定义无障碍动作(如果业务需要) let requestButtonAction = UIAccessibilityCustomAction(name: "start", target: self, selector: #selector(request)) dataDisclosureView.accessibilityCustomActions = [requestButtonAction] }
关键修正说明
- 父容器
accessibilityElements的优先级:当父容器设置了accessibilityElements数组后,子元素的isAccessibilityElement=true会被忽略,必须将需要VoiceOver识别的元素显式加入数组。之前的代码未将requestButton加入,导致其无法被VoiceOver识别,也影响自动化识别。 - 自动化元素的独立配置:iOS17+的
automationElements可以单独配置仅供测试识别的元素,无需将它们加入accessibilityElements(避免被VoiceOver识别)。 - 避免无效元素混入数组:用
compactMap { $0 }替代?? "",确保数组中只包含有效UI元素,避免类型错误。
内容的提问来源于stack exchange,提问作者AppleDeveloper
相关产品推荐
相关产品推荐

