如何解决UITextView长按链接时NSAttributedString.Key.link值可见的问题
嘿,我来帮你搞定这个UITextView链接长按显示值的问题!你遇到的是系统默认行为——长按UITextView里的链接时,会弹出展示NSAttributedString.Key.link对应值的菜单。下面给你几个实用的解决方案,按需选择就行:
方案一:拦截长按链接的系统默认行为(首推)
这个方法最精准,既能保留链接的点击功能,又能直接拦截长按触发的弹窗。利用UITextViewDelegate的方法,区分点击和长按交互:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { // 只允许点击触发链接行为,拦截长按的默认操作 return interaction == .invokeDefaultAction }
只要把你的UITextView的delegate设置好,这个方法就能生效。注意它要求iOS 10及以上版本,如果你需要兼容更低版本,再看下面的方案。
方案二:移除/禁用对应的长按手势
你之前尝试移除长按手势没生效,是因为UITextView的长按手势是内部管理的,得找对正确的方式移除:
方法A:遍历移除长按手势
在UITextView初始化完成后(比如viewDidLoad里),遍历它的所有手势识别器,移除长按类型的:
textView.gestureRecognizers?.forEach { gesture in if gesture is UILongPressGestureRecognizer { textView.removeGestureRecognizer(gesture) } }
不过这个方法会把文本选择的长按功能也一起禁用,如果你的UITextView不需要让用户选中文本,这个方法很省事;如果还需要文本选择,那方案一更适合。
方法B:子类化UITextView拦截长按
如果你想更彻底地控制手势,可以自定义一个UITextView子类,拦截长按手势的触发:
class CustomTextView: UITextView { override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { // 直接禁用所有长按手势 if gestureRecognizer is UILongPressGestureRecognizer { return false } return super.gestureRecognizerShouldBegin(gestureRecognizer) } }
之后把你项目里的UITextView替换成这个子类就行,同样会禁用所有长按行为。
方案三:自定义链接交互,完全脱离系统link属性
如果你想完全掌控链接的所有行为,也可以不用系统的NSAttributedString.Key.link,自己实现点击逻辑:
- 先给文本添加样式模拟链接,同时自定义一个属性存你的数据:
let linkString = NSMutableAttributedString(string: name) // 添加下划线模拟链接样式 linkString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0, name.count)) // 自定义属性存储你的userID和section数据 linkString.addAttribute(.init("customLinkData"), value: "name:\(userID)_section:\(section)", range: NSMakeRange(0, name.count))
- 给UITextView添加点击手势,自己处理点击逻辑:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTextViewTap(_:))) textView.addGestureRecognizer(tapGesture) @objc func handleTextViewTap(_ gesture: UITapGestureRecognizer) { let tapLocation = gesture.location(in: textView) guard let tapPosition = textView.closestPosition(to: tapLocation), let textRange = textView.tokenizer.rangeEnclosingPosition(tapPosition, with: .character, inDirection: .layout(.left)) else { return } let startOffset = textView.offset(from: textView.beginningOfDocument, to: textRange.start) // 获取自定义属性里的链接数据 if let customData = textView.attributedText?.attribute(.init("customLinkData"), at: startOffset, effectiveRange: nil) as? String { // 这里处理你的链接逻辑,比如解析customData拿到userID和section print("点击了自定义链接:\(customData)") } }
这种方式完全摆脱了系统的链接处理逻辑,自然不会有长按显示值的问题,你还能自定义任何交互行为。
内容的提问来源于stack exchange,提问作者iOSDev




