I first want to parse a large text file and collect all the necessary views before I finally display them. I have it working with an array of AnyView
but it's really not nice since it erases all types.
Basically, I just want a container to collect views inside until I finally display them.
So I was wondering if I could do something like this:
class Demo {
var content = VStack()
private func mapInput() {
// ...
}
private func parse() {
for word in mappedInput { // mappedInput is the collection of tags & words that is done before
switch previous {
case "i":
content.add(Text(word).italic())
case "h":
content.add(Text(word).foregroundColor(.green))
case "img":
content.add(Image(word))
}
}
}
}
And then do something with the VStack
later. But I get the following errors:
Error: Generic parameter 'Content' could not be inferred
Explicitly specify the generic arguments to fix this issue
Error: Missing argument for parameter 'content' in call
Insert ', content: <#() -> _#>'
Edit:
I have attempted to do it with the normal ViewBuilder
instead. The problem here is that it's all separate Text
s now that don't look like one text.
struct ViewBuilderDemo: View {
private let exampleInputString =
"""
<i>Welcome.</i><h>Resistance deepens the negative thoughts, acceptance</h><f>This will be bold</f><h>higlight reel</h><f>myappisgood</f>lets go my friend tag parsin in SwiftUI xcode 13 on Mac<img>xcode</img>Mini<f>2020</f><eh>One is beating oneself up, <img>picture</img>the other for looking opportunities. <h>One is a disempowering question, while the other empowers you.</h> Unfortunately, what often comes with the first type of questions is a defensive mindset. You start thinking of others as rivals; you have to ‘fight’ for something so they can't have it, because if one of them gets it then you automatically lose it.
"""
private var mappedInput: [String]
var body: some View {
ScrollView {
VStack(alignment: .leading) {
ForEach(Array(zip(mappedInput.indices, mappedInput)), id: \.0) { index, word in
if index > 0 {
if !isTag(tag: word) {
let previous = mappedInput[index - 1]
switch previous {
case "i":
Text("\(word) ")
.italic()
.foregroundColor(.gray)
case "h":
Text("\(word) ")
.foregroundColor(.green)
.bold()
case "f":
Text("\(word) ")
.bold()
case "eh":
Divider()
.frame(maxWidth: 200)
.padding(.top, 24)
.padding(.bottom, 24)
case "img":
Image(word)
.resizable()
.scaledToFit()
.frame(width: UIScreen.main.bounds.width * 0.7, height: 150)
default:
Text("\(word) ")
}
}
}
}
}
.padding()
}
}
init() {
let separators = CharacterSet(charactersIn: "<>")
mappedInput = exampleInputString.components(separatedBy: separators).filter{$0 != ""}
}
private func isTag(tag currentTag: String) -> Bool {
for tag in Tags.allCases {
if tag.rawValue == currentTag {
return true
}
}
return false
}
enum Tags: String, CaseIterable {
case h = "h"
case hEnd = "/h"
case b = "f"
case bEnd = "/f"
case i = "i"
case iEnd = "/i"
case eh = "eh"
case img = "img"
case imgEnd = "/img"
}
}