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 theContentViewstruct, add a@Statevariable inContentcalledcountriesthat contains an array of countries:@State var countries = ["USA", "Canada", "England","Cameroon", "South Africa", "Mexico" , "Japan", "South Korea"]
- Replace the
Textview in the body with a navigation view:NavigationView{ } - Add a list and a
ForEachloop withinNavigationViewthat displays the content of thecountriesvariable:List { ForEach(countries, id: \.self) { country in Text(country) }.onMove(perform: moveRow) } - Add a
.onMove(…)modifier to theForEachloop that calls themoveRowfunction: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 theListview:List { . . . } .navigationBarTitle("Countries", isplayMode: .inline) .navigationBarItems(trailing: EditButton()) - Implement the
moveRowfunction 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
ContentViewstruct 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.