基于父视图ID设置UI子视图Accessibility Identifier的方案咨询
问题核心原因解析
你第一段写在子视图类的代码无法生效,是因为你在accessibilityIdentifier的didSet回调中再次修改了自身的accessibilityIdentifier,这会无限触发didSet回调形成递归,系统会拦截这种异常重复赋值,所以最终不会生效。
最优实现方案
你第二段写在自定义父视图类的代码本身就是合理的实现方向,在此基础上可以做两处优化,无需额外强制关闭父视图的无障碍开关也能正常运行:
- 如果你不需要父视图本身被无障碍体系识别,直接在自定义父视图中重写
isAccessibilityElement默认返回false即可,这是苹果官方推荐的容器类视图的无障碍配置规范,不属于折衷处理方案。 - 如果需要保留父视图的无障碍识别能力,可重写父视图的
accessibilityElements属性,显式指定需要暴露的子视图元素,父视图本身不会出现在无障碍元素列表中,也不会影响子视图的标识识别。
你可以参考以下完整的实现示例:
class CustomContainerView: UIView { let textLabel = UILabel() let textField = UITextField() public override var isAccessibilityElement: Bool { get { false } set {} } public override var accessibilityIdentifier: String? { didSet { guard let parentId = accessibilityIdentifier else { return } // 避免重复赋值触发多余逻辑 if textLabel.accessibilityIdentifier != "\(parentId)_text_label" { textLabel.accessibilityIdentifier = "\(parentId)_text_label" } if textField.accessibilityIdentifier != "\(parentId)_text_field" { textField.accessibilityIdentifier = "\(parentId)_text_field" } } } }
如果你希望子视图自身处理后缀拼接,避免父视图代码冗余,也可以给子视图添加自定义前缀属性,避免递归问题:
class CustomLabel: UILabel { var accessibilityPrefix: String? { didSet { guard let prefix = accessibilityPrefix else { accessibilityIdentifier = nil return } accessibilityIdentifier = "\(prefix)_label" } } }
此时父视图的accessibilityIdentifier的didSet中只要给子视图的accessibilityPrefix赋值即可。
内容的提问来源于stack exchange,提问作者Retro
相关产品推荐
相关产品推荐

