You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何解决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,自己实现点击逻辑:

  1. 先给文本添加样式模拟链接,同时自定义一个属性存你的数据:
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))
  1. 给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

火山引擎 最新活动