Skip to main content

How to let users move rows in a list

About 3 minSwiftSwiftUIArticle(s)bloghackingwithswift.comcrashcourseswiftswiftuixcodeappstore

How to let users move rows in a list 관련

SwiftUI by Example

Back to Home

How to let users move rows in a list | SwiftUI by Example

How to let users move rows in a list

Updated for Xcode 15

SwiftUI provides two ways to let us move items in a list: a simple way supported on iOS 16.0 or later, and a more advanced way that works on older iOS versions too. Regardless of which approach you choose, you can also selectively disable moving a row using the moveDisabled() modifier.

The simple approach to moving works great if you're just moving your item around in an array, without adding any additional logic. To use it, use a data binding with your list and pass in the editActions parameter, like this:

struct ContentView: View {
    @State private var users = ["Glenn", "Malcolm", "Nicola", "Terri"]

    var body: some View {
        NavigationStack {
            List($users, id: \.self, editActions: .move) { $user in
                Text(user)
            }
        }
    }
}

Download this as an Xcode projectopen in new window

That immediately lets users drag the list rows around, and the users array will be updated as they do so. If you want to add swipe to delete as well, use .all rather than just .move.

If you want to disable movement for one row, use moveDisabled() with whatever criteria you have. For example, we could say that Glenn must always appear first in our list like this:

struct ContentView: View {
    @State private var users = ["Glenn", "Malcolm", "Nicola", "Terri"]

    var body: some View {
        NavigationStack {
            List($users, id: \.self, editActions: .move) { $user in
                Text(user)
                    .moveDisabled(user == "Glenn")
            }
        }
    }
}

Download this as an Xcode projectopen in new window

For the more complex approach to moving, we can attach an onMove(perform:) modifier to a ForEach inside a list, and have it call a method of our choosing when a move operation happens. That method needs to accept a source IndexSet and a destination Int, like this:

func move(from source: IndexSet, to destination: Int) {
    // move the data here
}

When moving several items it's always a good idea to move the later ones first so that you avoid moving other items and getting your indexes confused. Fortunately, Swift's sequences have a built-in way to move index sets for us, so we can just pass the parameters along and have it work correctly.

As an example, we could create a ContentView struct that sets up an array of three username strings, and asks SwiftUI to move them around calling a move() method. In order to activate moving – i.e., to make the drag handles appear – it also adds an edit button to the navigation stack so the user can toggle editing mode.

Here's the code:

struct ContentView: View {
    @State private var users = ["Paul", "Taylor", "Adele"]

    var body: some View {
        NavigationStack {
            List {
                ForEach(users, id: \.self) { user in
                    Text(user)
                }
                .onMove(perform: move)
            }
            .toolbar {
                EditButton()
            }
        }
    }

    func move(from source: IndexSet, to destination: Int) {
        users.move(fromOffsets: source, toOffset: destination)
    }
}

Download this as an Xcode projectopen in new window

Similar solutions…
How to let users delete rows from a list | SwiftUI by Example

How to let users delete rows from a list
How to change the tint color for individual list rows | SwiftUI by Example

How to change the tint color for individual list rows
How to add a badge to TabView items and List rows | SwiftUI by Example

How to add a badge to TabView items and List rows
How to set the background color of list rows using listRowBackground() | SwiftUI by Example

How to set the background color of list rows using listRowBackground()
Showing and hiding form rows | SwiftUI by Example

Showing and hiding form rows

이찬희 (MarkiiimarK)
Never Stop Learning.