I have somewhat unsuccessfully tried to figure out how to work with SwiftUI's ForEach view. By following resources such as this, this and this, it seems to me that given an array of strings:
var arrayOfStrings: [String] = ["String1", "String2", "String3"]
...each of the following implementations should work:
ForEach(arrayOfStrings, id: \.self) {
Text(arrayOfStrings[$0])
}
ForEach(1...arrayOfStrings.count, id: \.self) {
Text(arrayOfStrings[$0])
}
ForEach(arrayOfStrings, id: \.self) { string in
Text(string)
}
Yet each of them gives me a compile-time error or crashes the app at runtime.
The above is just example code, but if you need the full context of what I am trying to do, here it is:
struct Infobox<Content>: View where Content: View {
let edgeSize: CGFloat = 8
let color: Color = .neoblå
let content: Content
var body: some View {
VStack(spacing: 0) {
BoxSide(.top, withColor: color)
.frame(height: edgeSize)
.padding(.horizontal, 0)
content
.background(color)
BoxSide(.bottom, withColor: color)
.frame(height: edgeSize)
.padding(.horizontal, 0)
}
}
init(@ViewBuilder _ content: @escaping () -> Content) {
self.content = content()
}
init<T: View>(withHeader headerText: String, forContentArray contentArray: [(text: String, value: String)], splitInTwoColumns twoColumns: Bool, @ViewBuilder ignoreTheClosure: @escaping () -> T) where Content == VStack<TupleView<(HStack<TupleView<(Spacer, Text, Spacer)>>, HStack<TupleView<(VStack<ForEach<ClosedRange<Int>, Int, Text>>, VStack<ForEach<ClosedRange<Int>, Int, Text>>, Spacer, VStack<ForEach<ClosedRange<Int>, Int, Text>>, VStack<ForEach<ClosedRange<Int>, Int, Text>>)>>)>> {
var column1: [String] = []
var column2: [String] = []
var column3: [String] = []
var column4: [String] = []
let halfArray = contentArray.count/2
for (index, content) in contentArray.enumerated() {
if index+1 <= halfArray {
column1.append(content.text)
column2.append(content.value)
} else {
column3.append(content.text)
column4.append(content.value)
}
}
self.init() {
VStack(alignment: .leading) {
HStack() {
Spacer()
Text(headerText)
.font(.headline)
Spacer()
}
HStack {
VStack {
ForEach(column1, id: \.self) {
Text(column1[$0])
}
}
VStack {
ForEach(column2, id: \.self) {
Text(column2[$0])
}
}
Spacer()
VStack {
ForEach(column3, id: \.self) {
Text(column3[$0])
}
}
VStack {
ForEach(column4, id: \.self) {
Text(column4[$0])
}
}
}
}
}
}
}
Summary: Given an array of (String, String), create an Infobox() consisting of Text() elements divided into four columns (two for "keys" and two for the corresponding values).
If anyone has any ideas of how to fix those ForEach views, I'll give you a cookie :)
This one fails because $0
is a String
and you cannot index your string-array with a string
ForEach(arrayOfStrings, id: \.self) {
Text(arrayOfStrings[$0])
}
This one fails because array indices are 0-based -> Choose a 0 base range: 0..<arrayOfStrings.count
to avoid an "Index-out-of-bounds exception"
ForEach(1...arrayOfStrings.count, id: \.self) {
Text(arrayOfStrings[$0])
}
This one is generally correct, but you may have to reference your member scope-qualified self.arrayOfStrings
this applies to all SwiftUI code when your scope is a closure:
ForEach(arrayOfStrings, id: \.self) { string in
Text(string)
}
This is a more Swifty-way of doing the array access via index:
ForEach(arrayOfStrings.indices) {
Text(self.arrayOfStrings[$0])
}
struct ContentView: View {
let numbers = [1, 2, 3, 4, 5]
var body: some View {
VStack {
ForEach(Array(numbers.enumerated()), id: \.element) { index, number in
Text("Number \(number) is at index \(index)")
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With