List in SwiftUI

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.

share this post with friends

Picture of Nicola De filippo

Nicola De filippo

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve

1 comment

Leave a comment

Your email address will not be published. Required fields are marked *

Who I am

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve.

Follow Me Here

Get The Latest Updates

Periodically receive my super contents on coding and programming

join the family;)

Recent Posts