'Tappable portions within a string for SwiftUI

I'm trying to add tappable segments to a Text and I have most of it but I cannot make an array of Texts with .onTapGestures. How can I add the tap gestures to the Texts. The goal is to have a string such as "here is a phone: xxx-xxx-xxxx and here is a link: xxx.com. Go for it." and have xxx-xx-xxx and xxx.com tappable.


@available(iOS 14, *)
struct ConversationText: View {
    
    var text: String
    var connectMessageType: ConnectMessageType
    var stringArray = [String]()
    var phones = [String]()
    var weblinks = [String]()
    var textArray = [Text]()
    
    init(text: String, connectMessageType: ConnectMessageType) {
        self.text = text
        self.connectMessageType = connectMessageType
        
        stringArray = text.components(separatedBy: " ")
        phones = phones(from: text) ?? [String]()
        weblinks = weblinks(from: text) ?? [String]()
        textArray = makeTexts(from: stringArray)
    }
    
    var myColor: Color {
        connectMessageType == .me ? .secondaryYellow : .primaryBlue
    }
    
    var body: some View {
        textArray.reduce(Text(""), { $0 + $1 })
    }
    
    func phones(from text: String) -> [String]? {
        Tappables().getPhoneNumbers(from: self.text)
    }
    
    func weblinks(from text: String) -> [String]? {
        Tappables().getWebLinks(from: self.text)
    }
    
    func makeTexts(from stringArray: [String]) -> [Text] {
        var textArray = [Text]()
        for string in stringArray {
                if phones.contains(string) {
                    let text = Text(string+" ")
                        .foregroundColor(myColor)
//                        .onTapGesture {
//                            startCall(number: string, user: nil)
//                        }
                    textArray.append(text)
                } else if weblinks.contains(string) {
                    let text = Text(string+" ")
                        .foregroundColor(myColor)
//                        .onTapGesture {
//                            if let url = URL(string: string),
//                               UIApplication.shared.canOpenURL(url){
//                                UIApplication.shared.open(url)
//                        }
                    textArray.append(text)
                } else {
                    textArray.append(Text(string+" "))
                }
        }
        
        return textArray
    }
}```


Solution 1:[1]

Here is possible approach - use string formatted by Markdown.

Tested with Xcode 13.3 / iOS 15.4

demo

A main part:

Text("here is a phone: [xxx-xxx-xxxx](tel:xxx-xxx-xxxx) and here is a link: [xxx.com](asperi://apple.com). Go for it.")
    .onOpenURL {
        print(">> got: \($0)")
    }

Complete findings & code

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Asperi