You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI下iOS14兼容:自定义URL跳转新视图问题求助

iOS14 SwiftUI 自定义AttributedString链接点击解决方案

问题分析

在iOS14的SwiftUI场景下,直接使用Text组件的.onOpenURL修饰符无法触发自定义URL的点击回调,且无法直接使用UITextView的代理方法处理链接交互,同时iOS15+的.environment(\.openURL, ...)方案不兼容项目要求的iOS14版本,需要一种兼容iOS14的自定义链接点击实现方式。

解决方案

通过将UITextView封装为SwiftUI可用的UIViewRepresentable组件,利用UITextView的代理方法拦截链接点击,完美兼容iOS14,同时实现自定义跳转逻辑:

1. 封装可检测链接点击的文本组件

struct TapDetectableText: UIViewRepresentable {
    let attributedString: AttributedString
    let onLinkTap: (URL) -> Void
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.attributedText = NSAttributedString(attributedString)
        textView.isEditable = false
        textView.isSelectable = true
        textView.delegate = context.coordinator
        textView.backgroundColor = .clear
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.attributedText = NSAttributedString(attributedString)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(onLinkTap: onLinkTap)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        let onLinkTap: (URL) -> Void
        
        init(onLinkTap: @escaping (URL) -> Void) {
            self.onLinkTap = onLinkTap
        }
        
        func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
            onLinkTap(URL)
            return false // 阻止系统默认跳转
        }
    }
}

2. 重构你的文本视图实现

替换原有的TextLabelWithHyperlink使用封装后的组件,自定义链接处理逻辑:

private var hyperlinkText: some View {
    let firstURL = URL(string: "firstSCREEN=1")!
    let secondURL = URL(string: "secondSCREEN=2")!
    
    let completeString = "After clicking %@ first screen should be displayed and when you click %@ the second one should be presented."
    let stringArray = ["this link", "this next text with my custom link "]
    
    // 构建带链接属性的AttributedString
    var attrString = AttributedString(String(format: completeString, arguments: stringArray))
    for (index, targetString) in stringArray.enumerated() {
        guard let range = attrString.range(of: targetString) else { continue }
        attrString[range].link = [firstURL, secondURL][index]
        attrString[range].foregroundColor = .blue
        attrString[range].underlineStyle = .single
    }
    
    return TapDetectableText(attributedString: attrString) { url in
        if url == firstURL {
            // 打开第一个页面的逻辑
            print("Open first screen")
        } else if url == secondURL {
            // 打开第二个页面的逻辑
            print("Open second screen")
        } else {
            // 默认浏览器打开其他链接
            if UIApplication.shared.canOpenURL(url) {
                UIApplication.shared.open(url)
            }
        }
    }
    .font(.system(size: Constants.BottomDescription.fontSize))
}

方案说明

该方案通过UIViewRepresentable将UITextView封装为SwiftUI组件,既保留了UITextView原生的链接检测能力,又能在SwiftUI环境中使用。通过代理方法shouldInteractWith拦截链接点击事件,自定义处理跳转逻辑,同时返回false阻止系统默认的浏览器跳转行为,完全兼容iOS14版本。

内容的提问来源于stack exchange,提问作者sparafinski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 18:21:34