SwiftUI 实现拖拽功能时doDrop方法未触发问题求助
SwiftUI 拖拽功能问题修复方案
1. performDrop 不触发的修复
你自定义的DropDelegate仅实现了performDrop方法,缺少必填的放置校验逻辑,SwiftUI会默认判定放置操作不合法,因此不会走到最终的放置回调。需要在doDrop结构体中补充validateDrop方法,明确告知系统当前位置接受拖拽内容。
补充后的基础doDrop结构如下:
struct doDrop: DropDelegate { // 新增校验方法:告知系统当前放置合法 func validateDrop(info: DropInfo) -> DropProposal? { guard info.hasItemsConforming(to: ["public.text"]) else { return nil } return DropProposal(operation: .move) } func performDrop(info: DropInfo) -> Bool { guard info.hasItemsConforming(to: ["public.text"]) else { return false } if let item = info.itemProviders(for: ["public.text"]).first { item.loadItem(forTypeIdentifier: "public.text", options: nil) { data, error in DispatchQueue.main.async { if let str = data as? NSString as? String { print("拖拽内容:\(str)") } } } return true } return false } }
2. 获取放置目标信息的实现
如果需要拿到当前放置的目标位置信息,需要给DropDelegate增加传参,把目标对应的标识(比如条目索引、容器ID等)在初始化时传入即可。
以你当前的列表场景为例,如果要实现将某个条目拖拽到另一个条目上的逻辑,需要把onDrop修饰符挂载到每个列表元素上,同时传入当前元素的索引,完整可运行代码如下:
import SwiftUI struct ContentView: View { @State var stuff = ["ABC", "DEF","GHI","JKL","MNO"] var body: some View { List { ForEach(Array(stuff.enumerated()), id: \.element) { index, x in Text(x) .onDrag { NSItemProvider(object: x as NSString) } // 把当前条目的索引传给DropDelegate .onDrop(of: ["public.text"], delegate: doDrop(targetIndex: index, stuff: $stuff)) } } } struct doDrop: DropDelegate { // 存储放置目标的索引,以及绑定的数据源 let targetIndex: Int @Binding var stuff: [String] func validateDrop(info: DropInfo) -> DropProposal? { guard info.hasItemsConforming(to: ["public.text"]) else { return nil } return DropProposal(operation: .move) } func performDrop(info: DropInfo) -> Bool { guard info.hasItemsConforming(to: ["public.text"]) else { return false } if let item = info.itemProviders(for: ["public.text"]).first { item.loadItem(forTypeIdentifier: "public.text", options: nil) { data, error in DispatchQueue.main.async { guard let dragStr = data as? NSString as? String, let dragIndex = stuff.firstIndex(of: dragStr), dragIndex != targetIndex else { return } // 此处已经拿到拖拽源内容、源索引、目标索引,可以自定义排序逻辑 stuff.move(fromOffsets: IndexSet(integer: dragIndex), toOffset: targetIndex > dragIndex ? targetIndex + 1 : targetIndex) print("将\(dragStr)移动到索引\(targetIndex)位置") } } return true } return false } } }
如果是容器和条目层级的场景,只需要把传入的索引替换为容器ID、条目类型等你需要的标识即可。
内容的提问来源于stack exchange,提问作者Russ
相关产品推荐
相关产品推荐

