Is there any up to date way to convert links inside the text? I'm getting this kind of text from an API:
var someText: String = "with banks (for example to the sometimes controversial but leading exchange <a href="https://www.coingecko.com/en/exchanges/bitfinex">Bitfinex</a>)."
How can I convert that link inside to a clickable link with the proper name, in the example above: Bitfinex ?
The text could contain multiple links. SwiftUI now supports markdown, manually I could do it like:
Text("[Privacy Policy](https://example.com)")
but how do I do it for a received text from api with multiple links?
Looking for a Swift 5 & SwiftUI 3 solution.
CodePudding user response:
What you have is an html string. You can create a TextView
UIViewRepresentable
of an UITextView
and convert your html string into an NSAttributedString
using options NSAttributedString.DocumentType.html
. Don't forget to set the textview dataDetectorTypes
to .link
. Something like:
import SwiftUI
struct TextView: UIViewRepresentable {
var html: String
@State var font: UIFont?
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.dataDetectorTypes = .link
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.attributedText = html.htmlToAttributedString
uiView.font = font
}
}
You will need to add those helpers
extension Data {
var htmlToAttributedString: NSAttributedString? {
do {
return try NSAttributedString(data: self, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
print("error:", error)
return nil
}
}
}
extension StringProtocol {
var data: Data { .init(utf8) }
var htmlToAttributedString: NSAttributedString? { data.htmlToAttributedString }
}
Usage:
struct ContentView: View {
var html = #"with banks (for example to the sometimes controversial but leading exchange <a href="https://www.coingecko.com/en/exchanges/bitfinex">Bitfinex</a>. For more info <a href="https://www.google.com/">Google</a>).""#
var body: some View {
TextView(
html: html,
font: .systemFont(ofSize: 32)
).frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
CodePudding user response:
"...to display the text as it is, with the links inside but converted (clickable)...", you could try
this approach, which lets you use the SwiftUI Text
view.
struct ContentView: View {
var someText = #"with banks (for example to the sometimes controversial but leading exchange <a href="https://www.coingecko.com/en/exchanges/bitfinex">Bitfinex</a>). For more info <a href="https://www.google.com/">Google</a>. For bugs see <a href="https://stackoverflow.com/">Stack Overflow</a>.""#
var body: some View {
Text(LinksMaker.attributedString(from: someText))
}
}
class LinksMaker {
static func attributedString(from str: String) -> AttributedString {
var text = [AttributedString]()
if let theData = str.data(using: .utf8) {
let theString = try! NSAttributedString(data: theData, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
theString.enumerateAttributes(in: NSRange(location: 0, length: theString.length), options: []) { (attrs, range, _) in
if let rangex = Range(range, in: theString.string) {
var txt = String(theString.string[rangex])
if let url = attrs[.link] as? URL {
txt = "[\(txt)](\(url.absoluteString))"
}
text.append(try! AttributedString(markdown: txt))
}
}
}
return text.reduce("", { x,y in x " " y})
}
}