Home > OS >  How to add onTapGesture AND underline to specific word in a SwiftUI Text view?
How to add onTapGesture AND underline to specific word in a SwiftUI Text view?

Time:01-14

I need to make a specific underlined word be tappable within a paragraph of text for a SwiftUI view.

Currently my onTapGesture applies to the whole paragraph but I need it only on Text(labelOne) (AKA Action).

I cannot use onTapGesture AND .underline on Text(labelOne) because I get the error "Cannot convert value of type 'some View' to expected argument type 'Text'" if underline() is placed under onTapGesture {} OR "Cannot convert value of type 'some View' to expected argument type 'Text'" if I put onTapGesture{} under .underline().

In this case I am combining Text views, Text("Action") Text("end of first sentence.") Text("Body Text") so this is what prevents me from combining .onTapGesture with .underline()

It would be preferable to use a Button inside the paragraph so the user gets visual feedback that Action was pressed but not sure if that is possible without it being separate from the text?

enter image description here

If put Text in an HStack (which would allow me to add .underline() & .onTapGesture{} to a specific view) it looks bad if the sentence grows for Text(labelTwo), see below

enter image description here

struct TextView: View {
    let labelOne: String = "Action"
    let labelTwo: String = "end of first sentence."
    let text: String = "Begining of second sentence lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem"
    
    var body: some View {
        HStack {
            Text(labelOne) // <- Needs to be tappable, solely.
                .underline()
              Text(" \(labelTwo) ")
              Text(text)
        }
        .onTapGesture { // <- Applies to whole paragraph (BAD)
            print("Action pressed")
        }
    }
}

CodePudding user response:

You can solve this in three steps:

First, define a custom URL scheme for your app, e.g.

    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLName</key>
            <string>com.example.myapp</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myappurl</string>
            </array>
        </dict>
    </array>

This can be done in your target's Info tab: enter image description here

Secondly, change your first text to use Markdown, using Action as the link text and a url that uses your newly defined URL scheme, e.g.

Text("[\(labelOne)](myappurl://action)").underline()

Finally, add the .onOpenURL modifier. When you tap the link the app will try to open itself, and it can be handled by this modifier.

HStack {
    Text("[\(labelOne)](myappurl://action)").underline()  
    Text(" \(labelTwo) ")  
    Text(text)
}.onOpenURL { link in

    // do whatever action you want on tapping the link


}
  • Related