onDrag 是 SwiftUI 中用于实现拖拽(Drag and Drop)功能的修饰符,它允许将某个视图变成“可以拖拽的内容源”。
基本定义
SwiftUI 中 .onDrag 方法的签名:
func onDrag(_ data: @escaping () -> NSItemProvider) -> some View
它表示:当用户在这个视图上长按并开始拖拽时,提供一个 NSItemProvider,用于系统识别拖动的内容类型(如图像、文字、文件等)。
示例:拖拽图片
Image(nsImage: myImage)
.onDrag {
let provider = NSItemProvider(object: myImage)
return provider
}
当这张图片上开始拖动,macOS 会调用 .onDrag 中的闭包,将 myImage 封装为一个 NSItemProvider,系统就能识别这个拖拽操作并允许拖到 Finder、桌面或其他接受拖拽的 App。
支持内容类型
1、拖出文本内容:NSString、String:
Text("拖拽文本")
.onDrag { "hello" }
2、拖出图像:NSImage、UIImage;
3、拖出文件路径:URL(fileURLWithPath:);
4、拖出 PDF:NSData 或 NSFileWrapper;
5、拖出 URL: NSURL:
Text("拖拽 URL")
.onDrag { NSItemProvider(object: url as NSURL) }
6、拖出多种类型:NSItemProvider 支持多类型加载方式。
.onDrag {
let provider = NSItemProvider()
provider.registerDataRepresentation(forTypeIdentifier: UTType.rtf.identifier,visibility: .all) { completion in
completion(Data, nil)
return nil
}
return provider
}
使用registerDataRepresentation,可以支持富文本RTF、图片、文件、HTML、PDF等多种格式,允许懒加载数据(只有在 drop target真正需要时才生成Data)。
使用示例
1、拖出字符串
Text("拖我一下")
.onDrag {
NSItemProvider(object: "Hello World" as NSString)
}
2、拖出图片
Image(nsImage: image)
.onDrag {
NSItemProvider(object: image)
}
注意事项
1、.onDrag 只能用在 macOS / iPadOS / 支持拖拽的视图上。
2、字符串才能直接用 NSItemProvider(object:)。
3、NSItemProvider(object: attr.string as NSString) 会丢失所有富文本格式,因为 attr.string 只是纯文本。
4、只有 registerDataRepresentation 才能正确提供多媒体/二进制格式。
5、.onDrag 本身不创建文件,只给 Finder 数据,Finder决定要创建一个 .rtf、.txt、.png等文件。
总结
SwiftUI 的 .onDrag 实际上API 的统一封装:
1、macOS:NSDraggingSource + NSPasteboardItemProvider
2、iOS:UIDragInteraction + NSItemProvider
SwiftUI不支持处理拖拽逻辑,只提供一个数据构造回调。
当用户触发拖拽手势时,UIKit / AppKit捕获手势,调用闭包() -> NSItemProvider,系统根据provider 的类型标识符(UTI / UTType),决定拖拽内容支持的目标,系统启动拖拽会话。
.onDrag的唯一职责是,提供一个准确声明内容类型的NSItemProvider,真实拖拽系统由 UIKit / AppKit 驱动。
相关文章
1、Apple NSItemProvider类:https://fangjunyu.com/2025/07/09/apple-nsitemprovider%e7%b1%bb/
