SwiftUI .onDrag on an item within a Form make the all Form draggable

Viewed 480

I have made a simple drag and drop of capsule text item to drop on a Text zone. The targeted Text value is getting the dropped item as text and it changes is value.

The following code works correctly and I am sure it can be useful for beginners who want to perform drag & drop.

The problem I am encountering is that when the draggable item is contained in a Form, then the all form is dragged instead of only the selected item only.

To reproduce it just uncomment the Form { }

Am I missing something or is it really a bug.

import SwiftUI
import UniformTypeIdentifiers

struct DragView: View {
    var body: some View {
        //Form{
            HStack{
                DropText()
                VStack{
                    ForEach((1...10).reversed(), id: \.self) {
                        CapsuleText(text: "Test \($0)")
                    }
                }
            }
       // }
    }
}


struct DropText: View {
    @State var myText: String = "Glisser ici"
    @State var targeted: Bool = false
    @State private var onDrag = false
    
    var body: some View {
        VStack{Text(myText)}
            .font(.footnote)
            .padding()
            .foregroundColor(.white)
            .background(targeted ? Color.red : Color.green)
            .clipShape(Capsule())
            .onDrop(of: [UTType.text], delegate: DragRelocateDelegate(dropText: $myText, onDrag: $onDrag))
    }
}



struct CapsuleText: View {
    var text: String
    @State private var onDrag = false
    
    var body: some View {
        VStack{Text(text)}
            .font(.footnote)
            .padding()
            .foregroundColor(.white)
            .background(onDrag ? Color.gray : Color.blue)
            .clipShape(Capsule())
            .onDrag {
                self.onDrag = true
                return NSItemProvider(object: String(text) as NSString)
            }
    }
}

struct DragRelocateDelegate: DropDelegate {
    @Binding var dropText: String
    @Binding var onDrag: Bool
    
    func dropEntered(info: DropInfo) {
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        return DropProposal(operation: .move)
    }
    
    func performDrop(info: DropInfo) -> Bool {
        guard info.hasItemsConforming(to: [UTType.text]) else {
            return false
        }
        let items = info.itemProviders(for: [UTType.text])
        for item in items {
            _ = item.loadObject(ofClass: String.self) { str, _ in
                if let str = str {
                    dropText = str
                }
            }
        }
        return true
    }
}

Expected behavior

NOt expected behavior

0 Answers
Related