1

My end goal is to have a maneuverable list (like swiftui's native list) that reorders the position of items while you drag them.

I am trying to allow dragging and dropping of items in a LazyVGrid, but unlike the answer in SwiftUI | Using onDrag and onDrop to reorder Items within one single LazyGrid?, I am using Core Data, and therefore my array of items is not an observable object and therefore cannot be passed as an @Binding for easy reordering.

Here is what I have:

import SwiftUI


struct TopListTest: View {
    @Environment(\.managedObjectContext) var context
    @FetchRequest(sortDescriptors: [NSSortDescriptor(key: "order", ascending: true)])
    var array: FetchedResults<Item> //An array of items pulled from Core Data

    @State private var dragging: Item?

    var body: some View {
        NavigationView {
            ZStack(alignment: .top) {
                ScrollView {
                    LazyVGrid(columns: [GridItem(.adaptive(minimum: .greatestFiniteMagnitude))]) {
                        ForEach(array) { item in
                            listItemView(item: item)
                            .onDrag {
                                self.dragging = item
                                return NSItemProvider(object: String(item.order) as NSString)
                            }
                            .onDrop(of: ["Item"], delegate: DragRelocateDelegate(item: item, current: $dragging))
                        }
                    }
                }
            }
        }
    }
}


struct DragRelocateDelegate: DropDelegate {
    //Where I would like to pass Core Data array, this would only be a copy, however
    var item: Item
    @Binding var current: Item?

    func performDrop(info: DropInfo) -> Bool {
        if item != current {
            let from = current!.order
            let to = item.order
            if from != to {
                item.order = from
                current!.order = to
            }
        }
        return true
    }
}

struct listItemView: View {
    var item: Item

    var body: some View {
        HStack {
            Text("\(item.order)")
            Spacer()
            Text(item.name ?? "")
        }
    }
}

This code makes a simple list of core data entity Item which has an order which is just an id/position number and a name. This allows you to drag and drop items but it only swaps the position of two items and it does not automatically reorder as you drag like swiftui lists.

Elixir12
  • 33
  • 4

0 Answers0