In this post, I explain how to use the list to show a list of elements.
The first simple example:
struct ContentView: View { var body: some View { List { Text("Element One") Text("Element Two") } } }
The magic word is List, which has two text elements:
The better way to iterate a list is to use a ForEach:
struct ContentView: View { var body: some View { List { ForEach(1...10, id: \.self) { index in Text("Element \(index)") } } } }
To have:
What’s is the id? What’s its purpose? The id identifies uniquely every element of the list, in this case with \.self the id is the value of the element. In the index is stored the current value of the element.
The id is very important, so we can define it for our structure using the Identifiable protocol:
struct Vehicle: Identifiable { var id = UUID() var name: String var image: String }
Change the code in the example in this way:
struct ContentView: View { var vehicles = [Vehicle(name: "car", image: "car"), Vehicle(name: "bus", image: "bus"), Vehicle(name: "tram", image: "tram"), Vehicle(name: "bicycle", image: "bicycle")] var body: some View { List(vehicles) { vehicle in Text(vehicle.name) } } }
In the previous code is declared and initialized an array of Vehicle and the list iterates on that array, to have:
Custom Row
In the image field, I used the name from https://developer.apple.com/sf-symbols/ SanFrancisco symbols, you can use also your images to load them in the assets.
var body: some View { List(vehicles) { vehicle in HStack { Image(systemName: vehicle.image) Text(vehicle.name) } } }
The text is not aligned, to fix it we have to do some change, set the resizable property at the image and set a fixed size for the image. Before doing that is better to extract the code that shows the row to have clean code. From the contextual menu, select show code action and then extract subview. Rename the ExtractSubview in RowView.
struct RowView: View { var body: some View { HStack { Image(systemName: vehicle.image) Text(vehicle.name) } } }
There are some errors because the vehicle is not found, so fix it:
struct RowView: View { var vehicle: Vehicle var body: some View { HStack { Image(systemName: vehicle.image) Text(vehicle.name) } } }
Now change the image properties:
struct RowView: View { var vehicle: Vehicle var body: some View { HStack { Image(systemName: vehicle.image) .resizable() .frame(width: 60, height: 60) Text(vehicle.name) } } }
At the end change the code in the List:
var body: some View { List(vehicles) { vehicle in RowView(vehicle: vehicle) } }
To have:
Swipe action
With SwiftUI is simple to implement the swipe action to delete an element:
var body: some View { List { ForEach(vehicles) { vehicle in RowView(vehicle: vehicle) } .onDelete { (indexSet) in self.vehicles.remove(atOffsets: indexSet) } } }
Note that we have to use the ForEach because the onDelete is defined for the ForEach and not for the List.
We have also to change the declaration of the array in:
@State var vehicles = [Vehicle(name: "car", image: "car"), Vehicle(name: "bus", image: "bus"), Vehicle(name: "tram", image: "tram"), Vehicle(name: "bicycle", image: "bicycle")]
We have to add @State because we want to propagate the change of the vehicles in the view.
The complete code is:
struct Vehicle: Identifiable { var id = UUID() var name: String var image: String } struct ContentView: View { @State var vehicles = [Vehicle(name: "car", image: "car"), Vehicle(name: "bus", image: "bus"), Vehicle(name: "tram", image: "tram"), Vehicle(name: "bicycle", image: "bicycle")] var body: some View { List { ForEach(vehicles) { vehicle in RowView(vehicle: vehicle) } .onDelete { (indexSet) in self.vehicles.remove(atOffsets: indexSet) } } } } struct RowView: View { var vehicle: Vehicle var body: some View { HStack { Image(systemName: vehicle.image) .resizable() .frame(width: 60, height: 60) Text(vehicle.name) } } }
To have:
Note: English is not my native language, so I’m sorry for some errors. I appreciate it if your correct me.
1 comment