How it works
DropDelegate is a protocol you adopt to take fine-grained control of a drag-and-drop interaction landing on a view. Where the closure-based onDrop modifiers handle simple cases, a delegate lets you respond to every phase of a drop — when content enters, moves within, and leaves the drop region, whether the proposed drop is allowed, and how to extract the dropped items. Reach for it when a single drop callback isn't enough and you need to validate, preview, or stage the operation as the user drags.
Conform a type to DropDelegate
DropDelegate is a protocol, so you declare a value type that adopts it and supply the behavior the view will call into. Here the nested
struct ColorDrop: DropDelegateis that conformer, carrying a@Binding var droppedso it can write back into the view's state when a drop succeeds.Implement performDrop(info:) to consume the items
The only required member is
performDrop(info:), which the system calls when the user releases content over the view. It receives aDropInfodescribing the dropped items and returns aBoolto report whether the drop was accepted. In the example it flipsdropped = trueand returnstrueto signal success.Read the drop payload from DropInfo
Every delegate callback is handed a
DropInfo, the gateway to the in-flight drag — its location, the uniform types present, and the item providers you load data from. Optional members likevalidateDrop(info:),dropEntered(info:),dropUpdated(info:), anddropExited(info:)all receive this sameinfoso you can inspect and react throughout the gesture.Attach the delegate with onDrop(of:delegate:)
A DropDelegate only takes effect once a view installs it. The
onDrop(of:delegate:)modifier wires the conformer to a target, declaring which uniform types it accepts and which delegate handles them — here.onDrop(of: [.url], delegate: ColorDrop(dropped: $dropped))makes the rectangle a live drop zone for URLs.Drive view state from the delegate
Because the delegate is a plain value, you pass bindings into it so its callbacks can mutate SwiftUI state. The
$droppedbinding handed toColorDropletsperformDrop(info:)update@State private var dropped, which in turn re-renders the rectangle's fill and overlay text.
func dropEntered(info: DropInfo) { dropped = true } to ColorDrop so the zone turns green the moment a drag hovers over it, before the user even releases.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct DropDelegateDemo: View {
@State private var dropped = false
struct ColorDrop: DropDelegate {
@Binding var dropped: Bool
func performDrop(info: DropInfo) -> Bool {
dropped = true
return true
}
}
var body: some View {
VStack(spacing: 16) {
Text("Drag a URL here")
RoundedRectangle(cornerRadius: 12)
.fill(dropped ? Color.green : Color.gray.opacity(0.3))
.frame(width: 160, height: 100)
.overlay(Text(dropped ? "Dropped!" : "Drop Zone"))
.onDrop(of: [.url], delegate: ColorDrop(dropped: $dropped))
}
.padding()
}
}