Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Draggable Dropdestination animation

I'm trying to use draggable in combination with dropDestination to move around cells in a grid. Everything works except the animation in between drags.

struct PhotosGridViewDraggable: View {
    
    @State var draggedItem: Color?
    
    @State var colors: [Color] = [.red, .blue, .gray, .green, .pink, .yellow]
    
    @Namespace var animation
    
    var body: some View {
        GeometryReader { proxy in
            let hGap: CGFloat = 14
            let width = proxy.size.width - (hGap * 2)
            let cellWidth = (width / 3)
            let cellSize = CGSize(width: cellWidth, height: cellWidth * 1.5)
            
            let columns = [GridItem(.fixed(cellWidth)), GridItem(.fixed(cellWidth)), GridItem(.fixed(cellWidth))]
            
            LazyVGrid(columns: columns) {
                ForEach(colors.indices, id: \.self) { index in
                    let color = colors[index]
                    Rectangle()
                        .fill(color)
                        .frame(width: cellSize.width, height: cellSize.height)
                        .draggable(color, preview: {
                            RoundedRectangle(cornerRadius: 10)
                                .fill(.ultraThinMaterial)
                                .frame(width: 1, height: 1)
                                .onAppear {
                                    draggedItem = color
                                }
                        })
                        .dropDestination(for: Color.self, action: { items, location in
                            return false
                        }, isTargeted: { status in
                            if let draggedItem = draggedItem, status, draggedItem != color {
                                if let sourceIndex = colors.firstIndex(of: draggedItem), let destinationIndex = colors.firstIndex(of: color) {
                                    withAnimation { // PROBLEM: does nothing
                                        let sourceItem = colors.remove(at: sourceIndex)
                                        colors.insert(sourceItem, at: destinationIndex)
                                    }
                                }
                            }
                            
                        })
                }
            }
            
        }
    }
    
}

Expected:

enter image description here

Actual:

enter image description here

like image 972
tintin Avatar asked Nov 28 '25 14:11

tintin


1 Answers

The id argument is configured to use the key .element, which means that the view uses the value of each element as a unique identifier for the view's elements. This means that if the elements in the colors array are unique, this will work correctly.

struct PhotosGridViewDraggable: View {

@State var draggedItem: Color?

@State var colors: [Color] = [.red, .blue, .gray, .green, .pink, .yellow]

@Namespace var animation

var body: some View {
    GeometryReader { proxy in
        let hGap: CGFloat = 14
        let width = proxy.size.width - (hGap * 2)
        let cellWidth = (width / 3)
        let cellSize = CGSize(width: cellWidth, height: cellWidth * 1.5)
        
        let columns = [GridItem(.fixed(cellWidth)), GridItem(.fixed(cellWidth)), GridItem(.fixed(cellWidth))]
        
        LazyVGrid(columns: columns) {
            ForEach(Array(colors.enumerated()), id: \.element) { index, color in
             
                Rectangle()
                    .fill(color)
                    .frame(width: cellSize.width, height: cellSize.height)
                    .draggable(color, preview: {
                        RoundedRectangle(cornerRadius: 10)
                            .fill(.ultraThinMaterial)
                            .frame(width: 1, height: 1)
                            .onAppear {
                                draggedItem = color
                            }
                    })
                    .dropDestination(for: Color.self, action: { items, location in
                        return false
                    }, isTargeted: { status in
                        if let draggedItem = draggedItem, status, draggedItem != color {
                            if let sourceIndex = colors.firstIndex(of: draggedItem), let destinationIndex = colors.firstIndex(of: color) {
                                withAnimation { 
                                    let sourceItem = colors.remove(at: sourceIndex)
                                    colors.insert(sourceItem, at: destinationIndex)
                                }
                            }
                        }
                        
                    })
            }
        }
        
    }
}

}
like image 117
AdR Avatar answered Nov 30 '25 05:11

AdR



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!