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
相关产品推荐
相关产品推荐

