I'm not sure where to report this, so here it is.
If you have a list of items and you make them clickable and movable, moving one or more items in the list and then clicking will cause them to move. This is yet another reason that SwiftData needs to track onMove.
Minimal reproducible code:
//
// ContentView.swift
// exampleBug
//
// Create a new project.
// Replace the default Item class with the one below, and replace ContentView with its class below
// Run the app and add a few items a few seconds apart so you can tell them apart.
// Drag an item to a new position in the list.
// Click one of the checkboxes and watch the list positions change for no reason!
//
import SwiftUI
import SwiftData
@Model
final class Item {
var timestamp: Date
var checkbox: Bool = false
init(timestamp: Date) {
self.timestamp = timestamp
}
}
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State private var editMode = EditMode.inactive
@Query private var items: [Item]
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
HStack {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
Button("", systemImage: item.checkbox ? "checkmark.circle.fill" : "circle") {
item.checkbox.toggle()
try? modelContext.save()
}
}
}
.onMove(perform: { indices, newOffset in
var theItems = items
theItems.move(fromOffsets: indices, toOffset: newOffset)
})
}
.environment(\.editMode, $editMode)
.moveDisabled(false)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}
func addItem() {
withAnimation {
let newItem = Item(timestamp: Date())
modelContext.insert(newItem)
}
}
func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
}
}
}
#Preview {
ContentView()
.modelContainer(for: Item.self, inMemory: true)
}
code-block