SwiftUI provides several ways to iterate over collections, including the ForEach loop.
Unlike a SwiftUI List, which represents views in a single column, similar to a UITableView, ForEach provides more flexibility to break away from the single column. This can be useful for more complex repeating layouts, although you don’t get the same functionality found in a List, such as swipe gestures. This tutorial will cover some examples of when to use ForEach.
The following shows a very basic ForEach loop:
var body: some View {
ForEach(0..<5) { index in
Text(index.description)
.frame(width: 60, height: 30)
.background(Capsule().fill(Color.blue.opacity(0.6)))
}
}
We declare it within the body. The ForEach, in this case, is given a range of 0 to less than 5.
We then have a Text view within, that takes the index description. We then add some formatting to the Text view by providing a frame width and height along with a background.
If you preview this, you will see five verticle capsule-shaped items numbered 0 to 4.
To adjust this to render horizontally, we just put it in a HStack as follows:
HStack {
ForEach(0..<5) { index in
Text(index.description)
.frame(width: 60, height: 30)
.background(Capsule().fill(Color.blue.opacity(0.6)))
}
}
Running this in the preview will now show these arranged horizontally. Hopefully, at this point, you can start to see ways in which this might be useful either within or outside of a List.
If you want to pass in something other than a range, you can do something like this:
let tags = ["Important", "Urgent", "Team"]
var body: some View {
HStack {
ForEach(tags, id: \.self) { tag in
Text(tag)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(Capsule().fill(Color.blue.opacity(0.2)))
.foregroundColor(.blue)
}
}
...
We first declare our tags as an array of string type.
We then pass in tags into the ForEach. Note that we use the syntax id: \.self here. This is used with primitive types as SwiftUI needs a way to track what needs changing in the view if changes are needed.
We then iterate over and call each item “tag”. In this example, it will put three capsules on the screen called Important, Urgent, and Team.
To show how we can do this without id: \.self, we can use the following:
struct TagListView: View {
let discussionPoints = [
DiscussionPoint(title: "Meeting Agenda", tag: "Important"),
DiscussionPoint(title: "Budget Review", tag: "Finance"),
DiscussionPoint(title: "Project Updates", tag: "Development"),
DiscussionPoint(title: "Team Building", tag: "HR")
]
var body: some View {
HStack {
ForEach(discussionPoints) { point in
Text(point.tag)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(Capsule().fill(Color.blue.opacity(0.2)))
.foregroundColor(.blue)
}
}
}
}
struct DiscussionPoint: Identifiable {
let id = UUID()
let title: String
let tag: String
}
This approach is very similar but offers the ability to iterate over objects.
At the bottom, the DiscussionPoint struct conforms to the Identifiable protocol. This includes an ID that is generated with UUID().
At the top, we initialise discussion points by providing a title and a tag.
The ForEach loop iterates over discussionPoints, but note that the id: .self is no longer needed because DiscussionPoint conforms to Identifiable. This provides what is necessary for the ForEach to work with each item.
We get a similar output to the previous version when we preview this.
By adding ForEach loops and perhaps even nesting these loops, we can create more complex views. If you need to show data in a column, like a contacts list, email list etc… then you can wrap the ForEach in a List. We’ll cover that in the next tutorial.
Leave a Reply
You must be logged in to post a comment.