Moving rows in a list
In this section, we will create an app that implements a list view and allows the user to move/reorganize rows.
Getting ready
Let's start by creating a new SwiftUI app in Xcode called MovingListRows
.
How to do it…
To allow users to move rows, we need to add a .onMove(..)
modifier to the end of the list view's ForEach
loop. We also need to embed the list in a navigation view and add a navigationBarItems
modifier that implements an EditButton
component. The steps are as follows:
- Open
ContentView.swift
. Within theContentView
struct, add a@State
variable inContent
calledcountries
that contains an array of countries:@State var countries = ["USA", "Canada", "England","Cameroon", "South Africa", "Mexico" , "Japan", "South Korea"]
- Replace the
Text
view in the body with a navigation view:NavigationView{ }
- Add a list and a
ForEach
loop withinNavigationView
that displays the content of thecountries
variable:List { ForEach(countries, id: \.self) { country in Text(country) }.onMove(perform: moveRow) }
- Add a
.onMove(…)
modifier to theForEach
loop that calls themoveRow
function:ForEach(countries, id: \.self) { country in Text(country) }.onMove(perform: moveRow)
- Add the
.navigationBarTitle("Countries", displayMode: .inline)
and.navigationBarItems(trailing: EditButton())
modifiers to the end of theList
view:List { . . . } .navigationBarTitle("Countries", isplayMode: .inline) .navigationBarItems(trailing: EditButton())
- Implement the
moveRow
function at the end of the body variable's closing brace:private func moveRow(source: IndexSet, destination: Int){ countries.move(fromOffsets: source, toOffset: destination) }
- The completed
ContentView
struct should be as follows:struct ContentView: View { @State var countries = ["USA", "Canada", "England","Cameroon", "South Africa", "Mexico" , "Japan", "South Korea"] var body: some View { NavigationView{ List { ForEach(countries, id: \.self) { country in Text(country) } .onMove(perform: moveRow) } .navigationBarTitle("Countries", displayMode: .inline) .navigationBarItems(trailing: EditButton()) } } private func moveRow(source: IndexSet, destination: Int){ countries.move(fromOffsets: source, toOffset: destination) } }
Run the application in the canvas, on a simulator, or on a physical device. A click on the Edit button at the top-right corner of the screen displays a hamburger symbol to the right of each row. Click and drag the symbol to move the row on which the country is displayed:

Figure 2.8 – MovingListRows preview when running
Run the app live preview and move the rows up or down. Nice work!
How it works…
To move list rows, you need to add the list to a navigation view, add the .onMove(perform:)
modifier to the ForEach
loop, and add a .navigationBarItems(trailing: EditButton())
modifier to the list.
The moveRow(source: IndexSet, destination: Int)
function takes two parameters: the source, an IndexSet
argument representing the current index of the item to be moved, and the destination, an integer representing the destination of the row. The .onMove(perform:)
modifier automatically passes those arguments to the function.