SwiftUI において、リスト に登録した リストアイテム を 移動 する View を実装したかったのですが、 toolbar の EditButton を用いる実装では都度 Edit ボタン を クリック する必要があり、その手間を省けないかと思いました。 実装してみれば簡単なのですが、あまり サンプル も見つからなかったた事もあり、本記事で整理してみます。
Xcode: 12.4
Swift: 5
はじめに SwiftUI で リスト を実装
まずは、単純なリストを実装するところから始めます。
import SwiftUI
struct ContentView: View {
var body: some View {
SampleList()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ContentView.swift
単純に5つの アイテム を生成し、 リスト に表示する シンプル な リスト です。
SampleList.swift
struct SampleList: View {
struct Item: Identifiable {
let id = UUID()
let title: String
}
@State private var items: [Item] = (0..<5).map { Item(title: "Item #\($0)") }
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text(item.title)
}
}
}
}
}

EditButton を用いて、 リストアイテム を 移動 する
まずは、EditButton を用いた実装を紹介します。 なお、ここで NavigationView を追加していますが、追加せずとも動作するはずです。
以下の サイト を参考に、下記を追記しています。
- move function を定義
- リストアイテム の onMove の Perform アクション の Closure として指定
- リストの Modifier に toolbar を追加し、要素として EditButton を追加

SampleList.swift
struct SampleList: View {
struct Item: Identifiable {
let id = UUID()
let title: String
}
@State private var items: [Item] = (0..<5).map { Item(title: "Item #\($0)") }
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text(item.title)
}
.onMove(perform: move)
}
.navigationTitle("Navigation Title")
.toolbar {
EditButton()
}
}
}
private func move(source: IndexSet, destination: Int) {
items.move(fromOffsets: source, toOffset: destination)
}
}
Editボタン を クリック することで、編集 モード になり、 リスト が移動できるようになります。

リストアイテム を常に 移動 できるようにする
UI によっては、都度 Edit ボタン を クリック するのが煩雑な場合もあるかと思います。
次に紹介するのは、 リスト の アイテム が常に移動できるようになる サンプル です。
以下の サイト を参考に、以下を実装します。
- リスト の environment Modifier の中で、 EditMode.active を指定
https://developer.apple.com/documentation/swiftui/environmentvalues
https://developer.apple.com/documentation/swiftui/editmode
SampleList.swift
struct SampleList: View {
struct Item: Identifiable {
let id = UUID()
let title: String
}
@State private var items: [Item] = (0..<5).map { Item(title: "Item #\($0)") }
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text(item.title)
}
.onMove(perform: move)
}
.navigationTitle("Navigation Title")
.environment(\.editMode, .constant(EditMode.active))
}
}
private func move(source: IndexSet, destination: Int) {
items.move(fromOffsets: source, toOffset: destination)
}
}
このように、 Edit ボタン を クリック することなく、 リスト の アイテム が常に移動可能となります。

まとめ
- List の onMove モディファイア で move 部分を実装
- Navigation View の environment モディファイア で \.editMode を指定することで 常に リスト を編集状態にすることが可能