I have a long label that I want to make into a Text view. For example:
"This is a really long text that is guaranteed to wrap around into 2 lines. There might be a solution. Click me to find out!"
For this Text, I want the "Click me to find out!" to be (1) tappable and (2) display a popover focused on it.
My current solution uses an HStack. This is fine if the label used in the text isn't that long but it becomes a problem when the label is too long, like in the example above.
@State private var showPopover = false
...
HStack(spacing: 0) {
Text(LocalizationUtils.getMsg("This is a really long text that is guaranteed to wrap around into 2 lines. There might be a solution."))
Text("Click me to find out")
.underline()
.onTapGesture {
// display popover on tap
showPopover = true
}
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
Text("The popover displayed!")
}
I guess you do not want the gap between the two text elements.
In that case try this approach using AttributedString.
Example code:
struct ContentView: View {
@State private var showPopover = false
@State private var attributed = AttributedString()
var body: some View {
Text(attributed)
.tint(.black)
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
Text("The popover displayed!").padding()
}
.environment(\.openURL, OpenURLAction { url in
if url.scheme == "app", url.host == "show" {
showPopover = true
return .handled
}
return .systemAction
})
.padding()
.onAppear {
let clickString = "Click me to find out"
let markdown = """
This is a really long text that is guaranteed to wrap around into 2 lines. There might be a solution. [\(clickString)](app://show)
"""
do {
attributed = try AttributedString(markdown: markdown)
} catch {
attributed = AttributedString(markdown)
}
if let aRange = attributed.range(of: clickString) {
attributed[aRange].underlineStyle = .single
attributed[aRange].foregroundColor = .black
}
}
}
}