2

I am testing out the solution provided by Asperi here:

SwiftUI | Using onDrag and onDrop to reorder Items within one single LazyGrid?

so,

what I would like to do is to add a contextMenu on a cell, and if the user chooses to reorder cells, then would enable the onDrag and onDrop gestures.

I looked into the simultaneousGesture but, I am not sure how trigger the contextMenu while the view also has onDrag attached to it.

so I tried something like this:

...............

ScrollView(.vertical, showsIndicators: true) {
    LazyVGrid(columns: gridItems, spacing: 0) {
        ForEach(model.data) { d in
            GridItemView(d: d)
                .frame(width: side, height: side)
                .overlay(dragging?.id == d.id ? Color.white.opacity(0.8) : Color.clear)
                .contextMenu {
                    Button {
                        editCells.toggle()
                    } label: {
                        Label("Edit...", systemImage: "pencil")
                    }

                    // other options .....
                }
                .onDrag {
                    self.dragging = d
                    return NSItemProvider(object: String(d.id) as NSString)
                }
                .disabled(!editCells)
                .onDrop(of: [UTType.text], delegate: DragRelocateDelegate(item: d, listData: $model.data, current: $dragging))
                            .disabled(!editCells)
           }
        }
       .animation(.default, value: model.data)

...............

So, the contextMenu never triggers unless I remove the onDrag and onDrop gestures first.

Is there a way to use the contextMenu to "enter" an edit mode to allow drag and drop? Is there a way to make it work while the onDrag and onDrop gestures are installed on the view?

Asperi is right. For the curious as to how I got around doing this I used this conditional View extension:

extension View {
    /// Applies the given transform if the given condition evaluates to `true`.
    /// - Parameters:
    ///   - condition: The condition to evaluate.
    ///   - transform: The transform to apply to the source `View`.
    /// - Returns: Either the original `View` or the modified `View` if the condition is `true`.
    @ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}
zumzum
  • 17,984
  • 26
  • 111
  • 172

1 Answers1

2

The both use same gesture (LongPress) for activation, so there is direct conflict. A possible approach is to make onDrag conditional (toggled by some external command).

The Draggable/canDrag can be similar as Droppable/acceptDrop in https://stackoverflow.com/a/61081772/12299030.

Asperi
  • 228,894
  • 20
  • 464
  • 690