SwiftUI处理程序在markdown Text视图中捕获点击的链接



在Swift 5.5 SwiftUI中,现在可以在标记文本中拥有链接。是否可以使用它为Text视图中的子文本添加抽头处理程序?例如,我正在想象做如下的事情,但我还没有弄清楚如何构建一个适用于此的链接(我每次都会收到URL错误(。设置某种自定义url模式是否有效?有没有更好的解决方案,比如我可以添加到Text视图中,类似于UITextViewshouldInteractWith?目标是解决与这里提到的类似的问题,但不必回到UITextView或不使用ZStack包装HStacks或GeometryReaders。

let baseText = "apple banana pear orange lemon"
let clickableText = baseText.split(separator: " ")
.map{ "[($0)](domainThatImAllowedToCapture.../($0))" }
Text(.init(clickableText)).onOpenLink { link in
print(link.split(separator: "/").last) // prints "pear" if word pear is tapped.
}

您可以尝试类似于此示例代码的东西。它在你的baseText上循环,创建适当的链接,当链接被点击/操作时,你可以放更多的代码来处理它

struct ContentView: View {
let baseText = "apple banana pear orange lemon"
let baseUrl = "https://api.github.com/search/repositories?q="

var body: some View {
let clickableText = baseText.split(separator: " ").map{ "[($0)]((baseUrl)($0))" }
ForEach(clickableText, id: .self) { txt in
let attributedString = try! AttributedString(markdown: txt)
Text(attributedString)
.environment(.openURL, OpenURLAction { url in
print("---> link actioned: (txt.split(separator: "=").last)" )
return .systemAction
})
}
}
}

使用@workingdog描述的方法,我将其清理为以下工作解决方案:

import SwiftUI
struct ClickableText: View {
@Environment(.colorScheme) var colorScheme: ColorScheme

private var text: String
private var onClick: (_ : String) -> Void

init(text: String, _ onClick: @escaping (_ : String) -> Void) {
self.text = text
self.onClick = onClick
}
var body: some View {
Text(.init(toClickable(text)))
.foregroundColor(colorScheme == .dark ? .white : .black)
.accentColor(colorScheme == .dark ? .white : .black)
.environment(.openURL, OpenURLAction { url in
let trimmed = url.path
.replacingOccurrences(of: "/", with: "")
.trimmingCharacters(in: .letters.inverted)
withAnimation {
onClick(trimmed)
}
return .discarded
})
}

private func toClickable(_ text: String) -> String {
// Needs to be a valid URL, but otherwise doesn't matter.
let baseUrl = "https://a.com/"
return text.split(separator: " ").map{ word in
var cleaned = String(word)
for keyword in ["(", ")", "[", "]"] {
cleaned = String(cleaned.replacingOccurrences(of: keyword, with: "\(keyword)"))
}
return "[(cleaned)]((baseUrl)(cleaned))"
}.joined(separator: " ")
}
}

最新更新