如何在SwiftUI中创建超链接

56

在 Swift 中,可以使用 NSMutableAttributedString 在文本中嵌入链接,例如此处所示的链接

那么,在 SwiftUI 中要如何实现相同的效果呢?

我尝试了以下代码,但它并不符合我的期望:this

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack {
            Text("By tapping Done, you agree to the ")
            Button(action: {}) {
                Text("privacy policy")
            }
            Text(" and ")
            Button(action: {}) {
                Text("terms of service")
            }
            Text(" .")
        }
    }
}

SwiftUI目前还不支持任何“Attribute”。 - Mojtaba Hosseini
13个回答

0

iOS 15以下

import SwiftUI
import SwiftUIFlowLayout

public struct HyperlinkText: View {
    private let subStrings: [StringWithLinks]
    
    public init(html: String) {
        let newString = html.replacingOccurrences(of: "<a href=\'(.+)\'>(.+)</a>",
                                                          with: "@&@$2#&#$1@&@",
                                                          options: .regularExpression,
                                                          range: nil)
        self.subStrings = newString.components(separatedBy: "@&@").compactMap{ subString in
            let arr = subString.components(separatedBy: "#&#")
            return StringWithLinks(string: arr[0], link: arr[safe: 1])
        }
    }
    
    public var body: some View {
        FlowLayout(mode: .scrollable,
                   binding: .constant(false),
                   items: subStrings,
                   itemSpacing: 0) { subString in
            if let link = subString.link, let url = URL(string: link) {
                Text(subString.string)
                    .foregroundColor(Color(hexString: "#FF0000EE"))
                    .onTapGesture {
                        if UIApplication.shared.canOpenURL(url) {
                            UIApplication.shared.open(url)
                        }
                    }
                    .fixedSize(horizontal: false, vertical: true)
            } else {
                Text(subString.string).fixedSize(horizontal: false, vertical: true)
            }
        }
    }
}

struct StringWithLinks: Hashable, Identifiable {
    let id = UUID()
    let string: String
    let link: String?
    
    static func == (lhs: StringWithLinks, rhs: StringWithLinks) -> Bool {
        lhs.id == rhs.id
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

0
另一种有效的方法是使用.environment,它可以让您控制用户在文本中点击链接时发生的操作。例如,您可能希望在应用内部的webview中打开URL,而不是在设备浏览器中打开。
@State private var isPresentedPrivacyPolicy = false
@State private var isPresentedTermsOfUse = false

private let privacyPolicyURL = "https://privacypolicy.com"
private let termsOfUseURL = "https://termsofuse.com"

HStack{
    let privacyPolicyText = "By continuing you accept our [Privacy Policy](\(privacyPolicyURL)) and [Terms of Use](\(termsOfUseURL))."
    Text(privacyPolicyText)
    .environment(\.openURL, OpenURLAction { url in
        if url.absoluteString == privacyPolicyURL {
            isPresentedPrivacyPolicy.toggle()
        } else if url.absoluteString == termsOfUseURL {
            isPresentedTermsOfUse.toggle()
        }
        return .handled
    })
}
.sheet(isPresented: $isPresentedPrivacyPolicy) {
    NavigationStack {
        WebView(url: URL(string: privacyPolicyURL)!) 
        .ignoresSafeArea()
        .navigationTitle("Privacy Policy")
        .navigationBarTitleDisplayMode(.inline)
    }
}
.sheet(isPresented: $isPresentedTermsOfUse) {
    NavigationStack {
        WebView(url: URL(string: termsOfUseURL)!)
        .ignoresSafeArea()
        .navigationTitle("Terms of Use")
        .navigationBarTitleDisplayMode(.inline)
    }
}

还有 WebView:

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {

    let url: URL

    func makeUIView(context: Context) -> WKWebView {
        return WKWebView()
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        webView.load(request)
    }
}

-8

使用内置函数+,它看起来像魅力一样:

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack {
            Button(action: {

            }) {
                Text("By tapping Done, you agree to the ")
              + Text("privacy policy")
                  .foregroundColor(Color.blue)
              + Text(" and ")
              + Text("terms of service")
                  .foregroundColor(Color.blue)
              + Text(".")
            }
            .foregroundColor(Color.black)
        }
    }
}

22
这会使整个文本都可点击,而不仅仅是链接部分。在这种情况下,有两个链接,无法区分哪一个被点击了。 - Frankenstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接