Lists in SwiftUI

Aug 6, 2021 2 min read
Lists in SwiftUI

Of all SwiftUI’s view types, List is the one you’ll rely on the most. That doesn’t mean you’ll use it the most – I’m sure Text or VStack will claim that crown.

The job of List is to provide a scrolling table of data. In fact, it’s pretty much identical to Form, except it’s used for presentation of data rather than requesting user input. Don’t get me wrong: you’ll use Form quite a lot too, but really it’s just a specialized type of List.

Just like Form, you can provide List a selection of static views to have them rendered in individual rows:

List {
    Text("Hello World")
    Text("Hello World")
    Text("Hello World")
}

We can also switch to ForEach in order to create rows dynamically from an array or range:

List {
    ForEach(0..<5) {
        Text("Dynamic row \($0)")
    }
}

Sections

And of course we can combine that with sections, to make our list easier to read:

List {
    Section(header: Text("Section 1")) {
        Text("Static row 1")
        Text("Static row 2")
    }

    Section(header: Text("Section 2")) {
        ForEach(0..<5) {
            Text("Dynamic row \($0)")
        }
    }

    Section(header: Text("Section 3")) {
        Text("Static row 3")
        Text("Static row 4")
    }
}

Allow Row selection

I need to look into this, in the meantime check:

How to allow row selection in a list - a free SwiftUI by Example tutorial
Learn Swift coding for iOS with these free tutorials

Adjust List row separator visibility and color

SwiftUI provides two modifiers to control the way row separators look with its Lists, specifically listRowSeparator() for controlling whether separators are visible or not, and listRowSeparatorTint() for controlling the separator color.

List {
    ForEach(1..<100) { index in
        Text("Row \(index)")
            .listRowSeparator(.hidden)
            .listRowSeparatorTint(.red)
    }
}

Example 1

Here's a full implementation of List with some modifications for easy understanding.

import SwiftUI

struct ContentView: View {
    let websites = ["A", "B", "C"]

    var body: some View {
            VStack {
                VStack {
                    Text("Header")
                        .font(.title)
                }
                
                VStack {
                    List {
                        ForEach(websites, id: \.self) { friend in
                            Text(friend)
                                .font(.custom("Avenir Next Regular", size: 12))
                                .background(Color(.red))    // Sets background of current row content
                                .swipeActions(allowsFullSwipe: false) {     // Adds custom swipe actions
                                    Button {
                                        print("Muting conversation")
                                    } label: {
                                        Label("Mute", systemImage: "bell.slash.fill")
                                    }
                                    .tint(.indigo)
                                    
                                    Button(role: .destructive) {
                                        print("Deleting conversation")
                                    } label: {
                                        Label("Delete", systemImage: "trash.fill")
                                    }
                                }
                        }
                        .listRowBackground(Color.green) // Sets Row color or a custom color: .listRowBackground(Color("DarkBackground"))
                        .listRowInsets(EdgeInsets())    // Removes extra padding space in rows
                        .listRowSeparator(.hidden)      // Removed lines between items
                    }
                    .listStyle(PlainListStyle()) // Removes extra spaces around the whole List
                    .frame(height: CGFloat(websites.count) * CGFloat(max(45, 20 + 2 * 5)))
                }
                
                VStack {
                    Text("Text without extra space 🤓")
                }
                
                Spacer()
            }
            .background(Color.blue.ignoresSafeArea(.all, edges: .all))
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Great! Next, complete checkout for full access to ArturoFM.
Welcome back! You've successfully signed in.
You've successfully subscribed to ArturoFM.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.