Search code examples
swiftuilazyvgrid

SwiftUI: `onDrop` overlay not going away in LazyVGrid?


I am testing out Asperi's great answer to reordering cells:

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

The issue I have is the overlay does not reset when I simply enter drag mode and then drop in place, see cell 3:

enter image description here

I am using the exact code as found on the answer. So it seems like this line:

.overlay(dragging?.id == d.id ? Color.white.opacity(0.8) : Color.clear)

is not reacting properly?

Any idea how I can make the overlay to update and go back to clear?


Solution

  • Actually it is a SwiftUI bug, because in this scenario onDrag is called, but onDrop is NOT (that's wrong from D&D flow perspective).

    A possible workaround is to introduce additional in-progress state that will indicate that D&D really started. (Actually I would think about some refactoring to simplify delegate's interface, but for demo it is ok).

    Tested with Xcode 13.3 / iOS 15.4

    Here are changes:

      @State private var isUpdating = false // in-progress state
    
      // ...
    
      .overlay(dragging?.id == d.id && isUpdating ? // << additional condition
         Color.white.opacity(0.8) : Color.clear)
    
      // ...
    
      .onDrop(of: [UTType.text], delegate: DragRelocateDelegate(item: d, listData: $model.data, 
         current: $dragging, updating: $isUpdating)) // << transfer into delegate
    
      // ...
    
      func dropEntered(info: DropInfo) {
        updating = true      // << indicate that D&D begins
    
      // ...
    
      func performDrop(info: DropInfo) -> Bool {
        self.updating = false // << D&D finished