iOS无障碍:如何增大Label/TextView中AttributedString的触摸目标区域
问题描述
现有一个显示“View privacy settings and legal disclaimer”的UITextView,其中“privacy settings”和“legal disclaimer”是通过NSAttributedString创建的可点击链接,核心代码如下:
let style = NSMutableParagraphStyle() style.alignment = .center footerAttributedString.addAttributes([NSAttributedString.Key.foregroundColor: AppConstants.Tokens.Font.default, NSAttributedString.Key.font: SFProText.regular.of(size: 13), NSAttributedString.Key.paragraphStyle: style], range: NSRange(location: 0, length: footerString.count)) /// .... and so on
需满足iOS无障碍规范(交互按钮最小触摸高度44px),但已知ContentInsets方案无效,且增大字号无法通过UX设计团队审核,如何增大富文本的触摸检测高度?
解决方案
方法1:自定义UITextView重写hitTest方法
通过重写hitTest(_:with:)扩大触摸检测范围,同时确保TextView固有高度不低于44px,既不改变文字显示样式,又满足触摸区域要求:
class AccessibleTextView: UITextView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let originalHitView = super.hitTest(point, with: event) // 扩大垂直触摸检测范围,上下各延伸10px(可根据需求调整) let expandedBounds = bounds.insetBy(dx: 0, dy: -10) if expandedBounds.contains(point) { // 检查触摸点对应位置是否为链接 let charIndex = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) guard charIndex < textStorage.length else { return originalHitView } let attributes = textStorage.attributes(at: charIndex, effectiveRange: nil) if attributes[.link] != nil { return self // 返回自身以确保触摸事件被处理 } } return originalHitView } // 确保TextView固有高度至少为44px override var intrinsicContentSize: CGSize { var size = super.intrinsicContentSize size.height = max(size.height, 44) return size } }
使用时直接将原UITextView替换为AccessibleTextView即可。
方法2:添加透明辅助按钮
在TextView上叠加透明UIButton,覆盖需要扩大的触摸区域,手动处理链接跳转逻辑,适合链接数量较少的场景:
// 初始化TextView后添加辅助按钮 func setupAccessibleLinks() { // 隐私设置按钮 let privacyBtn = UIButton(type: .custom) privacyBtn.frame = CGRect(x: textView.frame.minX, y: textView.frame.minY, width: textView.frame.width, height: 44) privacyBtn.backgroundColor = .clear privacyBtn.addTarget(self, action: #selector(openPrivacySettings), for: .touchUpInside) textView.superview?.addSubview(privacyBtn) // 法律声明按钮(如果需要单独处理) let legalBtn = UIButton(type: .custom) legalBtn.frame = CGRect(x: textView.frame.minX, y: textView.frame.minY, width: textView.frame.width, height: 44) legalBtn.backgroundColor = .clear legalBtn.addTarget(self, action: #selector(openLegalDisclaimer), for: .touchUpInside) textView.superview?.addSubview(legalBtn) // 关闭TextView自身交互,避免冲突 textView.isUserInteractionEnabled = false } @objc private func openPrivacySettings() { guard let url = URL(string: "your-privacy-url") else { return } UIApplication.shared.open(url) } @objc private func openLegalDisclaimer() { guard let url = URL(string: "your-legal-url") else { return } UIApplication.shared.open(url) }
方法3:调整段落样式的行高
通过修改段落样式的lineHeightMultiple或lineSpacing,在不改变字号的前提下增大文本块整体高度,让TextView自适应高度后满足44px触摸要求:
let style = NSMutableParagraphStyle() style.alignment = .center // 通过lineHeightMultiple放大行高,13号字体设置为3.4左右可让整体高度接近44px style.lineHeightMultiple = 3.4 // 也可使用lineSpacing:style.lineSpacing = 28(需根据实际显示调整数值) footerAttributedString.addAttributes([ NSAttributedString.Key.foregroundColor: AppConstants.Tokens.Font.default, NSAttributedString.Key.font: SFProText.regular.of(size: 13), NSAttributedString.Key.paragraphStyle: style ], range: NSRange(location: 0, length: footerString.count))
这种方式对UX影响最小,仅通过行间距/行高放大文本区域,容易通过设计审核。
内容的提问来源于stack exchange,提问作者ashokds
相关产品推荐
相关产品推荐

