I would like to show paragraphs of text in a ForEach.
This was my latest attempt:
struct ContentView: View {
let bodyText = "This is a sample body text that will wrap naturally within the bounds of the container."
var body: some View {
WordWrapView(words: identifyWords(words: bodyText))
.padding()
}
func identifyWords(words: String) -> [IdentifiedWord] {
let wordsArray = words.split(separator: " ").map { String($0) }
var idCounter = 1
return wordsArray.reversed().map { word in
let identifiedWord = IdentifiedWord(id: String(idCounter), word: word)
idCounter += 1
return identifiedWord
}
}
}
struct IdentifiedWord: Identifiable {
let id: String
let word: String
}
struct WordWrapView: View {
let words: [IdentifiedWord]
var body: some View {
GeometryReader { geometry in
self.createWrappedWords(in: geometry.size)
}
}
func createWrappedWords(in size: CGSize) -> some View {
var width: CGFloat = 0
var height: CGFloat = 0
return ZStack(alignment: .topLeading) {
ForEach(words) { word in
self.wordView(for: word.word)
.alignmentGuide(.leading, computeValue: { d in
if (abs(width - d.width) > size.width) {
width = 0
height -= d.height
}
let result = width
if word == self.words.last! {
width = 0 // last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: { _ in
let result = height
if word == self.words.last! {
height = 0 // last item
}
return result
})
}
}
}
func wordView(for text: String) -> some View {
Text(text)
.padding([.horizontal], 4)
.padding([.vertical], 2)
.background(Color.gray.opacity(0.2))
.cornerRadius(4)
}
}
The problem is that some words are overlapping other words.
Am I on the right track here? I reversed the array because I'm showing arabic words, and the ForEach is placing the words in reverse order...