如何实现UISearchBar取消按钮的VoiceOver无障碍适配?
解决UISearchBar在VoiceOver下的键盘与取消按钮无障碍问题
针对你遇到的两个问题——VoiceOver下切换元素后键盘不自动收起、动态显示的取消按钮无法被VoiceOver识别,我给你两个方向的实用解决方案:
一、让取消按钮被VoiceOver正确识别
UISearchBar的取消按钮属于系统私有子视图,动态显示时可能无法被VoiceOver及时扫描到,你可以通过以下两种方法修复:
方法1:手动定位按钮并配置无障碍属性
在调用setShowsCancelButton(true)后,遍历搜索栏的子视图找到取消按钮,手动设置它的无障碍标签和属性:
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { if UIAccessibilityIsVoiceOverRunning() { self.searchBar?.setShowsCancelButton(true, animated: true) // 等待动画完成后再查找按钮,确保视图已加载 DispatchQueue.main.async { let cancelButton = searchBar.subviews.flatMap { $0.subviews }.first { guard let button = $0 as? UIButton else { return false } return button.titleLabel?.text == NSLocalizedString("Cancel", comment: "") } as? UIButton // 配置无障碍属性,让VoiceOver能识别并朗读 cancelButton?.accessibilityLabel = "取消搜索" // 替换为符合你APP语境的标签 cancelButton?.accessibilityTraits = .button cancelButton?.isAccessibilityElement = true } } }
方法2:发送无障碍布局更新通知
如果不想遍历子视图,可以在按钮显示后发送通知,让VoiceOver重新扫描界面元素:
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { if UIAccessibilityIsVoiceOverRunning() { self.searchBar?.setShowsCancelButton(true, animated: true) // 等待动画结束后发送通知,确保按钮已完全显示 DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { UIAccessibility.post(notification: .layoutChanged, argument: self.searchBar) } } }
二、替代方案:直接根据VoiceOver焦点状态收起键盘
其实你也可以不用依赖取消按钮,而是监听VoiceOver的焦点变化,当搜索栏失去焦点时自动收起键盘,从根源解决键盘残留的问题:
实现代码示例
override func viewDidLoad() { super.viewDidLoad() // 监听VoiceOver焦点变化通知 NotificationCenter.default.addObserver( self, selector: #selector(handleAccessibilityFocusChange), name: UIAccessibility.elementFocusedNotification, object: nil ) } @objc private func handleAccessibilityFocusChange(_ notification: Notification) { guard UIAccessibilityIsVoiceOverRunning(), let focusedElement = notification.object as? UIView else { return } // 如果焦点不在搜索栏及其子视图上,收起键盘 if !focusedElement.isDescendant(of: searchBar) && !searchBar.isDescendant(of: focusedElement) { searchBar.resignFirstResponder() } } // 记得在页面销毁时移除监听 deinit { NotificationCenter.default.removeObserver( self, name: UIAccessibility.elementFocusedNotification, object: nil ) }
这个方案不需要额外显示取消按钮,完全根据VoiceOver的操作逻辑自动管理键盘,更符合无障碍用户的使用习惯。
建议在VoiceOver环境下反复测试两种方案,选择最贴合你APP交互逻辑的实现方式。
内容的提问来源于stack exchange,提问作者Rose Badoux
相关产品推荐
相关产品推荐

