0

I'm trying to display a Text with different URLs in swiftUI but face an issue with string interpolation.

I used the instruction here to add a custom URL scheme to my test app and when I use a basic test URL it works:

Text("[\(text)](urlschemetest://action)")
.onOpenURL { link in
   print("LINK: \(link)")
}

When I create the the same with a string interpolation within the URL part though the link doesn't work anymore.

Text("[\(text)](urlschemetest://\(actionVariable))")
.onOpenURL { link in
   print("LINK: \(link)")
}

Is there a way to have string interpolation to work or to populate the URL dynamically from a variable?

I assume I'm missing something simple but could not find anything related to this issue with my searches.

The goal is to use an array of words and connect each to its own URL. I currently use reduce on the array to build the string:

arrayObj.reduce(Text(""), {
    $0 + Text("[\($1.word)](baps://action/\($1.urlAction!)) ") + Text(" ")
} )
Slamit
  • 465
  • 1
  • 6
  • 21
  • you could try using AttributedString: `Text(try! AttributedString(markdown: "[\(text)](urlschemetest://\(actionVariable))"))`. See also this link: https://stackoverflow.com/questions/57744392/how-to-make-hyperlinks-in-swiftui – workingdog support Ukraine Feb 10 '23 at 23:07

1 Answers1

1

Use this example code (using AttributedString or Link) to ...have string interpolation to work or to populate the URL dynamically from a variable..

struct ContentView: View {
    @Environment(\.openURL) var openURL
    
    let query = "?q=swiftui&atb=v201-4__&hps=1&ia=web"
    let prompt = "Search for SwiftUI"
    
    var body: some View {
        VStack (spacing: 55) {
            // using AttributedString
            if let txt = try? AttributedString(markdown: "[\(prompt)](https://duckduckgo.com/\(query))") {
                Text(txt)
                    .environment(\.openURL, OpenURLAction { url in
                        print("\n---> Text: \(url)")
                        return .systemAction
                    })
            }
            // alternative, using Link
            if let linkUrl = URL(string: "https://duckduckgo.com/\(query)") {
                Link(prompt, destination: linkUrl)
                    .environment(\.openURL, OpenURLAction { url in
                        print("\n---> Link: \(url)")
                        return .systemAction
                    })
                    .foregroundColor(.red)
            }
        }
    }
}

EDIT-1:

Your question was: Is there a way to have string interpolation to work or to populate the URL dynamically from a variable?, now you are saying Is there a way to have that without a variable?.

What variable are you referring to?

With your .reduce, I suggest you use String, and then after getting the results use the AttributedString, such as:

     let results = arrayObj.reduce("", {
          $0 + "[\($1.word)](baps://action/\($1.urlAction)) " + " "
      } )
            
     if let txt = try? AttributedString(markdown: results) {
         Text(txt)
     }

Note, do not use forced unwrapping ! in your code, it is a recipe for a crash.

  • Thank you for answering. Is there a way to have that without a variable? I have a ForEach loop and use .reduce so I'm not sure it would work or be efficient to use :S – Slamit Feb 11 '23 at 18:46
  • updated my answer with your new question using the `.reduce` scheme. – workingdog support Ukraine Feb 11 '23 at 23:43
  • "AttributedString(markdown: results)" works ! Thank you for that. Checking a little further I realised I could call a function of my own too and create a proper AttributedString with all the required properties. – Slamit Feb 13 '23 at 11:57