13

I want to dynamically deliver content and display hyperlinks, but it can’t be delivered dynamically and doesn’t work

let linkTitle = "Apple Link"
let linkURL = "http://www.apple.com"
let string = "[Apple Link](http://www.apple.com)"
            
Text(string)        // Not working

Text("[Apple Link](http://www.apple.com)")  // Working
            
Text("[\(linkTitle)](http://www.apple.com)")    // Working
            
Text("[\(linkTitle)](\(linkURL))")  // Not working
            
kgaidis
  • 14,259
  • 4
  • 79
  • 93
gaohomway
  • 2,132
  • 1
  • 20
  • 37
  • hmm, does not work for me as well. You may have to resort to: "Link(linkTitle, destination: URL(string: linkURL)!)" – workingdog support Ukraine Jul 18 '21 at 07:49
  • @workingdog I am implementing hashtags(#) and mentions(@) Text very perfect, I only need to customize the URL Schemes, but unfortunately I can’t pass the string dynamically – gaohomway Jul 18 '21 at 08:06

4 Answers4

19

Short Answer

Wrap the string in AttributedString(markdown: my_string_here):

let string: String = "[Apple Link](http://www.apple.com)"
Text(try! AttributedString(markdown: string))

Extension

extension String {
  func toMarkdown() -> AttributedString {
    do {
      return try AttributedString(markdown: self)
    } catch {
      print("Error parsing Markdown for string \(self): \(error)")
      return AttributedString(self)
    }
  }
}

Long Answer

SwiftUI Text has multiple initializers.

For String:

init<S>(_ content: S) where S : StringProtocol

For AttributedString:

init(_ attributedContent: AttributedString)

When you declare a static string, Swift is able to guess whether the intent is to use a String or AttributedString (Markdown). However, when you use a dynamic string, Swift needs help in figuring out your intent.

As a result, with a dynamic string, you have to explicitly convert your String into an AttributedString:

try! AttributedString(markdown: string)
kgaidis
  • 14,259
  • 4
  • 79
  • 93
7

you can try this taken from: How to show HTML or Markdown in a SwiftUI Text? halfway down the page.

extension String {
    func markdownToAttributed() -> AttributedString {
        do {
            return try AttributedString(markdown: self) /// convert to AttributedString
        } catch {
            return AttributedString("Error parsing markdown: \(error)")
        }
    }
}
struct ContentView: View {
    let linkTitle = "Apple Link"
    let linkURL = "https://www.apple.com"
    let string = "[Apple Link](https://www.apple.com)"
       
    @State var textWithMarkdown = "[Apple Link](https://www.apple.com)"
    
    var body: some View {
        VStack {

            Text(textWithMarkdown.markdownToAttributed()) // <-- this works
            
            Text(string)        // Not working

            Text("[Apple Link](http://www.apple.com)")  // Working
                        
            Text("[\(linkTitle)](http://www.apple.com)")    // Working
                        
            Text("[\(linkTitle)](\(linkURL))")  // Not working
        }

    }
}
7

Add another .init in text.

struct ContentView: View {
    
    let linkTitle = "Apple Link"
    let linkURL = "http://www.apple.com"
    let string = "[Apple Link](http://www.apple.com)"
    
    var body: some View {
    
        Text(.init(string))     // <== Here!
        
        Text("[Apple Link](http://www.apple.com)")  // Working
        
        Text("[\(linkTitle)](http://www.apple.com)")    // Working
        
        Text(.init("[\(linkTitle)](\(linkURL))"))  // <== Here!
    }
}
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52
1

To define markdown string separately and then pass it to text, we should explicitly convert it to a localized string key. Because otherwise, SwiftUI will just treat this as a regular string and will not parse it internally.

let markdownStr = "Hello, **world**! Check out our [website](https: //example.com)!"
Text (LocalizedStringKey (markdownStr))
AbdelAli
  • 796
  • 1
  • 6
  • 6