Skip to main content

List の編集

並べ替え可能にする

swift
List {
ForEach ... {
...
}
.onMove { src, dst in
}
}

編集モードにするボタンを配置

swift
EditButton()

編集モード固定する

swift
List {
}
.environment(\.editMode, .constant(EditMode.active))

編集モードをコードから参照

swift
@Environment(\.editMode) var editMode
..
var isEditing: Bool {
editMode?.wrappedValue.isEditing ?? false
}

onMove つけてると並べ替え出来てしまう(並べ替え用のボタンは出ないが) ↓

swift
@State var editActive: Bool = false
..
Button(editActive ? "Done" : "Edit") {
editActive.toggle()
}
..
List {
ForEach {

}
.onDelete { indexes in
appData.routePoints.remove(atOffsets: indexes)
}
.onMove { src, dst in
appData.books.move(fromOffsets: src, toOffset: dst)
}
.moveDisabled(!editActive)
// .deleteDisabled(true)
}
.environment(\.editMode, .constant(editActive ? EditMode.active : EditMode.inactive))

複数選択の行を削除 配列から IndexSet に変換している

swift
Button("Delete Selected Rows", role: .destructive) {
let indexes = IndexSet(selectedRoutePoints.compactMap({ appData.routePoints.firstIndex(of: $0) }))
appData.routePoints.remove(atOffsets: indexes)
}

見た目系で、各行の要素に設定する

swift
List {
ForEach {
Xxxx
.listRowBackground(Color.clear) // タップのときに背景色がつけないようにする
.listRowSeparator(.hidden) // 行間の線を消す
}
}

ボタンにだけ反応したいが行全体にイベントが持っていかれて、同じ行の他のボタンにまで反応してしまう → buttonStyle を設定すれば良い

swift
Button {
..
}
.buttonStyle(.plain)
// .buttonStyle(.borderless)

SwiftData 使用時の並べ替え

swift
@Query(sort: \EventLocation.order) private var eventLocations: [EventLocation]

...

List {
ForEach(eventLocations) { eventLocation in
}
.onMove { src, dst in
moveItems(src, dst)
}
.onDelete { idxs in
deleteItems(idxs)
}
}
.environment(\.editMode, .constant(EditMode.active))

...

func moveItems(_ src: IndexSet, _ dst: Int) {
var items = eventLocations // copy
items.move(fromOffsets: src, toOffset: dst)

for (i, item) in items.enumerated() {
item.order = i
}
try? modelContext.save()
}

func deleteItems(_ idxs: IndexSet) {
}

削除ボタンについて

onDelete や、swipeActionrole: .destructive だと表示上、即時消えてしまうので swipeAction.tint(.red) する

ただ、swipeAction だと EditMode.active 設定すると反応しない

swift
@State private var isDeleteConfirmationDialogPresented: Bool = false

...

List {
ForEach(eventLocations) { eventLocation in
HStack {
...
}
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button("Delete", role: .destructive) {
isDeleteConfirmationDialogPresented = true
}
}
}