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)
    }
}
相关推荐
上海合宙LuatOS2 小时前
LuatOS框架的使用(1)
java·开发语言·单片机·嵌入式硬件·物联网·ios·iphone
小鹿软件办公7 小时前
苹果因通信问题撤回面向旧款 iPhone 和 iPad 的系统更新
ios·iphone
Thomas_YXQ17 小时前
Unity3D在ios平台下内存的优化详解
开发语言·macos·ios·性能优化·cocoa
zhyongrui1 天前
SwiftUI 光晕动画性能优化:消除托盘缩放卡顿的实战方案
ios·性能优化·swiftui
TheNextByte11 天前
如何通过 6 种方式删除 iPhone/iPad 上的文件
ios·iphone·ipad
WeiAreYoung1 天前
uni-app Xcode制作iOS谷歌广告Google Mobile Ads SDK插件
ios·uni-app
2501_916008891 天前
iOS 开发助手工具,设备信息查看、运行日志、文件管理等方面
android·ios·小程序·https·uni-app·iphone·webview
编程之路从0到11 天前
React Native新架构之iOS端初始化源码分析
react native·ios·源码剖析·新架构·初始化流程
2501_915921431 天前
在没有源码的前提下,怎么对 Swift 做混淆,IPA 混淆
android·开发语言·ios·小程序·uni-app·iphone·swift
00后程序员张2 天前
对比 Ipa Guard 与 Swift Shield 在 iOS 应用安全处理中的使用差异
android·开发语言·ios·小程序·uni-app·iphone·swift