How to Reorder List rows in SwiftUI List
source link: https://sarunw.com/posts/swiftui-list-onmove/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
How to Reorder List rows in SwiftUI List
Table of Contents
SwiftUI List provides an easy way to enable Reorder functionality by applying the onMove(perform:)
modifier to items in a List.
onMove(perform:)
accept a closure that gets called when items in the List view are moved.
A closure takes two arguments, an IndexSet
of moving items and a new destination position in Int
.
.onMove { fromOffsets: IndexSet, toOffset: Int in
}
You can easily support sarunw.com by checking out this sponsor.
Sponsor sarunw.com and reach thousands of iOS developers.
How to Reorder List rows in SwiftUI List
To enable the SwiftUI List rows reordering, you need to do the following steps.
The onMove
modifier only works with ForEach
, so you need to use ForEach
to populate your List view.
Create Data Source
Since you want to move an item in a List view, your data source must be mutable.
In this example, I use a @State
variable as a data source.
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]
Create a List view with ForEach
The onMove
modifier only works with ForEach
, so we need to populate our List view using ForEach
.
struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]
var body: some View {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}
}
}
}
Apply onMove modifier on ForEach
Apply the onMove
modifier on ForEach
to enable the reorder function.
struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]
var body: some View {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}.onMove { from, to in
// TODO: move the data source.
}
}
}
}
Move items in Data Source
The onMove
modifier doesn't automatically move an item in your data source. You have to do it yourselves.
The onMove
's closure takes two arguments, an IndexSet
of moving items and a new destination position in Int
.
Swift Array
has a move(fromOffsets:toOffset:)
method that match the two arguments we got.
extension MutableCollection {
mutating func move(
fromOffsets source: IndexSet,
toOffset destination: Int
)
}
We mutate the data source inside the onMove
's closure, contacts.move(fromOffsets: from, toOffset: to)
.
struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]
var body: some View {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}.onMove { from, to in
contacts.move(fromOffsets: from, toOffset: to)
}
}
}
}
That's all we need to do to enable List row reordering.
What does onMove do
By enabling the reordering function by attaching the onMove(perform:)
modifier, users can reorder the list item by Long-press on the row that you want to move, then drag it to the destination.
Long-press
Users can Long-press on any row to move that particular row.
Long-press to reorder.
Items in EditMode
In the Edit mode, SwiftUI also shows a drag handler on the trailing side of the row content to indicate that list rows can be moved around.
There are two options to enter the Edit mode.
- Using the
EditButton
- Setting the
.editMode
environment value
I will use EditButton
in this case.
struct ContentView: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]
var body: some View {
NavigationView {
List {
ForEach(contacts, id: \.self) { contact in
Text(contact)
}.onMove { from, to in
contacts.move(fromOffsets: from, toOffset: to)
}
}
.toolbar {
// 1
EditButton()
}
}
}
}
I added the edit button on a navigation bar 1 to allow users to enter the Edit mode.
Once you enter the edit mode by tapping the "Edit" button, you will see the drag handler at the end of each row.
Reorder items in Edit Mode.
You can easily support sarunw.com by checking out this sponsor.
Sponsor sarunw.com and reach thousands of iOS developers.
How to conditionally Disable the Reorder ability
If you want to disable the reorder ability, you can do that by passing nil
to the onMove
.
ForEach(contacts, id: \.self) { contact in
Text(contact)
}
.onMove(perform: nil)
Here is an example where we control reorder ability with the boolean value, enableMove
.
struct ReorderExample: View {
@State private var contacts = [
"John",
"Alice",
"Bob",
"Foo",
"Bar"
]
// 1
@State private var enableMove = true
var body: some View {
NavigationView {
List {
Toggle("Enable Move", isOn: $enableMove)
ForEach(contacts, id: \.self) { contact in
Text(contact)
}
// 2
.onMove(perform: enableMove ? move: nil)
}
.toolbar {
EditButton()
}
}
}
// 3
func move(from: IndexSet, to: Int) {
contacts.move(fromOffsets: from, toOffset: to)
}
}
1 A state variable use to control reorder ability.
2 We use enableMove
to conditionally disable reorder ability. We disable it by set perform closure as nil
.
3 We extract a move logic out as a separate function to improve readability.
Disable the reorder ability by passing nil to the onMove.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK