'SwiftUI LazyVGrid Drag and Drop animation bug

I have created a minimal working example of a LazyVGrid with drag and drop. If I move an item fast and move to the corner of the display and drop it there, the animation moves to the wrong place and disappears after some time. The actual item is at the correct position.

I have added my code below.

Drag and Drop bug

import SwiftUI
import UniformTypeIdentifiers

struct SameSizeView: View {
    @Namespace private var animation
    @State private var dragging: MyRect?
    @State private var rects = [
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect(),
        MyRect()
    ]
    
    let columns = [
        GridItem(
            .fixed(UIScreen.main.bounds.width / 2),
            spacing: MyRect.spacing,
            alignment: .topTrailing
        ),
        GridItem(
            .fixed(UIScreen.main.bounds.width / 2),
            spacing: MyRect.spacing,
            alignment: .topLeading
        )
    ]
    
    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            LazyVGrid(columns: columns, alignment: .center, spacing: MyRect.spacing) {
                ForEach(rects) { rect in
                    rect
                        .matchedGeometryEffect(id: rect.id, in: animation)
                        .onDrag {
                            self.dragging = rect
                            return NSItemProvider(object: rect.id.uuidString as NSString)
                        }
                        .onDrop(of: [UTType.text], delegate: MyDropDelegate(item: rect, listData: $rects, current: $dragging))
                    
                }
            }
        }
        .animation(.default, value: rects)
    }
}

struct MyRect: View, Identifiable, Equatable {
    var id = UUID()
    @State var color = Color.init(.sRGB, red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1), opacity: 1)
    
    static var spacing: CGFloat = 16
    
    var body: some View {
        Rectangle()
            .fill(color)
            .frame(
                width: UIScreen.main.bounds.width / 2 - MyRect.spacing * 1.5,
                height: 2 * 62 + MyRect.spacing
            )
    }
    
    static func == (lhs: MyRect, rhs: MyRect) -> Bool {
        return lhs.id == rhs.id
    }
}



struct MyDropDelegate: DropDelegate {
    let item: MyRect
    @Binding var listData: [MyRect]
    @Binding var current: MyRect?
    
    func dropEntered(info: DropInfo) {
        if item != current {
            let from = listData.firstIndex(of: current!)!
            let to = listData.firstIndex(of: item)!
            
            if listData[to] != current! {
                listData.move(fromOffsets: IndexSet(integer: from),
                              toOffset: to > from ? to + 1 : to)
                UIImpactFeedbackGenerator(style: .light).impactOccurred()
            }
        }
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        return DropProposal(operation: .move)
    }
    
    func performDrop(info: DropInfo) -> Bool {
        self.current = nil
        return true
    }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source