From the blog

"New Features in SwiftUI (iOS15), Part Two"

Lists have become more powerful in iOS15, some of the new features/improvements done in lists are as below:

1. Swipe Actions

2. Refreshable

3. ListRowSeparator and ListRowSeparatorTint

4. Bindings as List Iterator

Swipe Actions

Left and right swipe actions like edit, delete, etc for list items can be added using the swipeActions modifier.

List {
    ForEach(user.cities, id: \.self) { city in
        VStack {
            // cell content goes here
        }
        .swipeActions {
            Button(role: .destructive) {
                user.cities = user.cities.filter {$0 != city}
            } label: {
                Label("Delete", systemImage: "trash")
            }
        }
    }
}

We can also specify the swipe directions as leading or trailing as per our requirement using edge parameter

.swipeActions(edge: .leading) {

}

or 

.swipeActions(edge: .trailing) {

}

To enable/disable full swipe, allowsFullSwipe can be used. By default, allowsFullSwipe is true

.swipeActions(allowsFullSwipe: false) {

}

Refreshable

A new modifier “refreshable” is added to make pull to refresh easier. Using this modifier we can provide an action that will be executed once the user pulls down the content of the list/scrollable view from the top.

List {
    
}
.refreshable {
    // Action goes here
}

ListRowSeparator And ListRowSeparatorTint

Two modifiers are introduced to customise the appearance of separators of list rows:

1. listRowSeparator is used to specify if separators in the list are visible or not.

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

2. listRowSeparatorTint is used to specify the color of the separator.

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

Using bindings in Lists / ForEach

Starting from iOS15, SwiftUI lets us create a List or ForEach from a binding. This is useful if some properties of list items being displayed gets updated over time.

struct ContactsView: View {
    
    struct Contact: Identifiable {
        var id: Int
        var name: String
        var isActive = false
    }
    @State var contacts = [
        Contact(id: 1, name: "Contact1"),
        Contact(id: 2, name: "Contact2"),
        Contact(id: 3, name: "Contact3")
    ]
    
    var body: some View {
        List($contacts) { $contact in
            Text(contact.name)
            Toggle("Contact is active", isOn: $contact.isActive)
        }
    }
}

In the above example, isActive property can change at runtime. The advantage of using binding here is that if value of isActive is updated for one particular item only that item is updated/re-rendered, the complete view is not re-rendered. 

Leave a Reply

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