けれども、SwiftUI を使うと、非常に簡単に実装することができるので説明します。
Sponsor Link
List と ForEach と .onMove
使用する要素は、以下のものです。
- List
- ForEach
- .onMove
普通のリスト表示には、List を使うかと思いますが、List での表示を、ForEach に分解します、その要素に対して、.onMove modifier を使って、どのように移動するかを実装します。
.onMove の実装
onMove に対しては、引数として、source :IndexSet と destination :Int が渡されてきます。
”どこから” ”どこへ” 移動させるかの情報です。
実は、Array の move メソッドは、同じ引数をとりますので、配列ないの順番入れ替えであれば、onMove で渡された引数をそのまま move に渡すと期待する動作になります。
struct ContentView: View {
@State private var dataList = ["item1", "item2", "item3"]
var body: some View {
List {
ForEach( dataList, id: \.self) { data in
Text(data)
.padding()
}
.onMove(perform: self.move)
}
}
func move(from source: IndexSet, to destination: Int) {
dataList.move(fromOffsets: source, toOffset: destination)
}
}
Mac と iOS での動作の違い
Mac 上では、上記のコードだけで、リストの要素の入れ替えが可能となります。
iOS では、リストのスクロールとジェスチャーが重複していますので、明示的にエディットモードに入る必要があります。
エディットモードは、environment の .editMode で制御することができますので、iOS では、以下のようにすると並べ替え操作を行うことができます。
struct ContentView: View {
@State private var dataList = ["item1", "item2", "item3"]
var body: some View {
List {
ForEach( dataList, id: \.self) { data in
Text(data)
.padding()
}
.onMove(perform: self.move)
}
.environment(\.editMode, .constant(.active)) // ⬅️ iOS 対応
}
func move(from source: IndexSet, to destination: Int) {
dataList.move(fromOffsets: source, toOffset: destination)
}
}
上記では、常に active にしていますが、通常は、エディットモード切り替えをリストのタイトル部分等に表示して実装します。
注意点: macOS で使う時に気をつけること
macOS で不用意に使うと 想定しないクラッシュが発生することがあります。
[SwiftUI] List/ForEach の onMove についての メモ書き [SwiftUI] onMove を自分で実装する
自分で実装することも難しくはないので、検討した方が良いです。
まとめ:List の要素の並べ替えの実装方法のポイントは4つ
以下の点を考慮することで、非常に簡単に実装できます。
- ForEach の要素に対して、onMove を設定する
- onMove でデータソースのリスト要素の並べ替えを行う
- データソースが Array であれば、Array の move 関数を使うと非常に簡単に実装できる
- iOS であれば、.editMode を設定しないと、並べ替えモードにならない
説明は、以上です。
Sponsor Link