iOS 支持文本消息识别链接及电话号码的长按复制(同 WhatsApp)

因 App 对标 WhatsApp,所以要实现文本消息长按手机号或者链接时弹窗显示对应提示,并支持复制、打开链接(url)。

先上 WhatsApp 效果图

长按手机号 长按链接

代码实现

App 内的文本消息内容展示时通过 UITextView 实现的,故给其添加一个 extension 来实现手机号、链接的识别以及高亮效果。

Swift 复制代码
enum TextLinkType {
    case none
    case link
    case phoneNumber
}

extension UITextView {
    // 识别长按类型,并处理高亮
    func longPressType(_ gesture: UILongPressGestureRecognizer) -> TextLinkType {
        let location = gesture.location(in: self)
        guard let textPosition = closestPosition(to: location) else { return .none }
        if let range = tokenizer.rangeEnclosingPosition(textPosition, with: .word, inDirection: UITextDirection(rawValue: 1)),
           let nsRange = convertToNSRange(textRange: range, textView: self) {
            let isLinkInfo = isRangeInLink(nsRange, in: text)
            if isLinkInfo.isLink, let range = isLinkInfo.matchRange {
                highlightRange(range, in: self, with: UIColor(0x0A84FF, alpha:0.3))
                showActionSheetForLinkType(isLinkInfo.linkType, link: substring(from: range, in: text) ?? "", range: range)
                return isLinkInfo.linkType
            }
        }
        return .none
    }
    
    // 处理文字显示颜色
    private func highlightRange(_ range: NSRange, in textView: UITextView, with backgroundColor: UIColor, textColor: UIColor? = nil) {
        let attributedString = NSMutableAttributedString(attributedString: textView.attributedText)
        attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: backgroundColor, range: range)
        if let textColorRef = textColor {
            attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: textColorRef, range: range)
        }
        textView.attributedText = attributedString
    }
    
    private func substring(from nsRange: NSRange, in string: String) -> String? {
        if let range = Range(nsRange, in: string) {
            return String(string[range])
        }
        return nil
    }
    
    // 获取是否是链接,链接 range 以及 链接类型
    private func isRangeInLink(_ range: NSRange, in string: String) -> (isLink: Bool, matchRange: NSRange?, linkType: TextLinkType) {
        if let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) {
            // Check if the range is URL link
            let matches = detector.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
            for match in matches {
                if NSIntersectionRange(range, match.range).length > 0 {
                    return (true, match.range, .link)
                }
            }
        }
        
        // Check if the range is a phone number
        let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
        if let matches = detector?.matches(in: text, options: [], range: range), !matches.isEmpty {
            return (true, range, .phoneNumber)
        }
        
        return (false, nil, .none)
    }
    
    // Range 转换
    private func convertToNSRange(textRange: UITextRange, textView: UITextView) -> NSRange? {
        let beginning = textView.beginningOfDocument
        let start = textRange.start
        let end = textRange.end
        let location = textView.offset(from: beginning, to: start)
        let length = textView.offset(from: start, to: end)
        return NSRange(location: location, length: length)
    }
    
    // 弹窗处理
    private func showActionSheetForLinkType(_ linkType: TextLinkType, link: String, range: NSRange) {
        // 根据链接类型显示长按弹窗
        
        // 点击弹窗后清除高亮
        self.highlightRange(range, in: self, with: .clear)
    }
}
相关推荐
2501_915921436 小时前
移动端 WebView 视频无法播放怎么办 媒体控件错误排查与修复指南
android·ios·小程序·https·uni-app·iphone·webview
大熊猫侯佩7 小时前
WWDC 25 极地冰原撸码危机:InlineArray 与 Span 的绝地反击
swift·apple·wwdc
AirDroid_cn15 小时前
手机防沉迷新招:安卓手机如何成为管理iPhone的遥控器?
android·ios·智能手机·iphone·ipad
林大鹏天地16 小时前
iOS borderWidth为0.5边框上下不均匀问题探究和解决
ios
东坡肘子1 天前
Xcode 26 beta 4,要崩我们一起崩 | 肘子的 Swift 周报 #096
swiftui·swift·apple
CocoaKier1 天前
推荐一个历代iPhone设备型号网站,比维基百科好用
ios·apple
笑尘pyrotechnic1 天前
自动布局视图来实现聊天室的界面
ui·ios·objective-c
2501_915909062 天前
Charles中文版使用教程 高效抓包与API调试常见问题处理
android·ios·小程序·https·uni-app·iphone·webview
键盘敲没电2 天前
【iOS】KVO
学习·macos·ios·objective-c·cocoa
00后程序员张2 天前
iOS软件性能监控实战指南 开发到上线的完整流程解析
android·ios·小程序·https·uni-app·iphone·webview