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:
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.