I received an assignment to fetch text from the cloud database and convert it into a Text view
the rules are as follows: each word that starts with $ and ends with $ needs to be bold:
let str = "$random$"
let extractStr = "random"
Text(extractStr).bold()
each word that starts with ~ and ends with ~ needs to be clickable
let str = "~random~"
let extractStr = "random"
Text(extractStr).onTapGesture { print("tapping")}
each word that starts with % and ends with % needs to be red
let str = "%random%"
let extractStr = "random"
Text(extractStr).foregroundColor(Color.red)
and so on. different kinds of rules.
the overall target is to combine all the text into one paragraph.
It is possible when summing the Texts views without any gestures, But when I try to sum a Textview with a tap gesture, everything falls apart
for example, I created a long text
let text1 = "$Hello$ my dear fellows. I want to provide #you# this
%awesome% long Text. I shall $talk$ a bit more to show
@you@ that when the text is $very very long$ , $it
doesn’t behave as I wanted to$. \n\n Lets #investigate a
bit more# and see how this text can behave. \n\n ~you can
click me~ and ~you can click me also~ and if you need
to, you have ~another clickable text~"
and my desired outcome is this:
So this is what I tried
I converted it into an array:
let array1 = [$Hello$, my, dear, fellows., I, want, to, provide,
#you#, this, %awesome, long, text. ......]
after that, I did some checking and created an array of Texts:
var arrayOfText: [Text] = []
I did some logic and ended up with this:
arrayOfText = [Text("Hello").bold(), Text("my"),
Text("dear").underline(),
Text("fellows."), Text("I"), Text("want"), Text("to")
Text("provide"), Text("you").foregroundColor(.blue),
Text("this"), Text("awesome").foregroundColor(.red),
Text("long"), Text("text"), ... ... ...
Text("another clickable text").onTapGesture{print("tap")}] // <-- Text with tap gesture, this is not valid...
Now I can loop through the texts and sum them all:
var newText: Text = Text("")
for text in arrayOfText {
newText = newText + text
}
but It fails... I cant assign Text with tap gesture into an array of Text
I got this error:
Could not cast value of type 'SwiftUI.ModifiedContent<SwiftUI.Text, SwiftUI.AddGestureModifier<SwiftUI._EndedGesture<SwiftUI.TapGesture>>>' (0x7fc8c08e9758) to 'SwiftUI.Text' (0x7fff8166cd30).
So I tried to do some workaround and set the array to be an array of AnyView
var arrayOfText: [AnyView] = []
but then when I cast Text into AnyView
I receive this error:
Cast from 'AnyView' to unrelated type 'Text' always fails
any ideas how can I pull this off?
UPDATE
I tried using Asperi method:
struct StringPresenter: View {
let text1 = "hello $world$ I am %a% &new&\n\n~robot~"
var body: some View {
ForEach(text1.split(separator: "\n"), id: \.self) { line in
HStack(spacing: 4) {
ForEach(line.split(separator: " "), id: \.self) { part in
self.generateBlock(for: part)
}
}
}
}
private func generateBlock(for str: Substring) -> some View {
Group {
if str.starts(with: "$") {
Text(str.dropFirst().dropLast(1))
.bold()
} else
if str.starts(with: "&") {
Text(str.dropFirst().dropLast(1))
.font(Font.body.smallCaps())
} else
if str.starts(with: "%") {
Text(str.dropFirst().dropLast(1))
.italic().foregroundColor(.red)
} else
if str.starts(with: "~") {
Text(str.dropFirst().dropLast(1))
.underline().foregroundColor(.blue).onTapGesture { print("tapping ")}
}
else {
Text(str)
}
}
}
}
But it doesn't work with long text. the whole views collapse on each other
This is how it looks Like:



