1

I'm currently building a ToDo List App in SwiftUI. One feature that I'd really like to implement is the ability to sort your List manually, so I've integrated the functionality using a .onMove modifier on my ForEach loop populating my List, but I still had to toggle EditMode manually, so I set the EditMode of the list to be .active as follows:

import SwiftUI

struct ContentView: View {
@State private var items = ["1", "2", "3"]
@State var editMode: EditMode = .active

var body: some View {
    List {
        ForEach(items, id: \.self) { item in
            Text("Item \(item)")
        }
        .onMove(perform: { _, _  in })
    }
    .environment(\.editMode, $editMode)
}
}

But I'm not happy with this Implementation, as I still have to use the grip from EditMode, and it also breaks SwipeActions as well as Button functionality.

So how can I move List Items without using EditMode?

newb
  • 172
  • 1
  • 9
  • Does this answer your question https://stackoverflow.com/a/58770635/12299030? – Asperi Nov 22 '21 at 16:52
  • not really, as I still have the set grabbing point and also having editmode enabled breaks the button functionality to mark a task as done. @Asperi – newb Nov 22 '21 at 17:00
  • I actually found the solution through another answer of yours, related to that linked post, so thank you! @Asperi – newb Nov 24 '21 at 13:29

1 Answers1

3

Based on Asperi's answer on this question I implemented drag and drop Gestures to fix that problem as follows:

struct ContentView: View {

@State var items = [Item(id: 1), Item(id: 2), Item(id: 3), Item(id: 4)]
@State private var dragging: Item?

var body: some View{
    List{
        ForEach(items){ item in
            Text("Item \(item.id)")
                .onDrag {
                    self.dragging = item
                    return NSItemProvider(object: NSString())
                }
                .onDrop(of: [UTType.text], delegate: DragDelegate(current: $dragging))
        }
        .onMove(perform: {_, _  in })
    }
}
}

Using a DropDelegate implementation:

struct DragDelegate<Item: Equatable>: DropDelegate {
@Binding var current: Item?

func dropUpdated(info: DropInfo) -> DropProposal? {
    DropProposal(operation: .move)
}

func performDrop(info: DropInfo) -> Bool {
    current = nil
    return true
}
}

Note: the Items now have to conform to Identifiable & Equatable so the minimal Implementation is:

struct Item: Identifiable, Equatable{
let id: Int
}

and you also need to import:

import UniformTypeIdentifiers

in order to use drag and drop functionality

newb
  • 172
  • 1
  • 9