SwiftUI拖拽功能在iOS模拟器正常,Mac Catalyst版本失效排查
Mac Catalyst中SwiftUI拖拽放置失败的原因及解决办法
问题描述
我在SwiftUI应用中实现了拖拽功能,该功能在iOS模拟器中运行完全正常,但在Mac Catalyst版本中无法正常工作:拖拽手势可被识别,但放置操作执行失败。
原实现代码
struct ContentView: View { @State private var items = ["Item 1", "Item 2", "Item 3"] var body: some View { ScrollView { LazyVStack { ForEach(items, id: \.self) { item in Text(item) .padding() .background(Color.blue) .cornerRadius(8) .foregroundColor(.white) .onDrag { NSItemProvider(object: item as NSString) } } } } .onDrop(of: ["public.text"], delegate: CustomDropDelegate(items: $items)) } } struct CustomDropDelegate: DropDelegate { @Binding var items: [String] func performDrop(info: DropInfo) -> Bool { guard let item = info.itemProviders(for: ["public.text"]).first else { return false } item.loadItem(forTypeIdentifier: "public.text", options: nil) { (data, error) in DispatchQueue.main.async { if let textData = data as? Data, let text = String(data: textData, encoding: .utf8) { self.items.append(text) } } } return true } }
原因分析
Mac Catalyst和iOS对NSItemProvider处理public.text类型数据的逻辑存在差异:
- iOS上,通过
NSItemProvider(object: NSString)创建的提供者,加载数据时会以Data类型返回 - 但在Mac Catalyst中,相同代码会直接返回
NSString实例,原代码只处理了Data的情况,导致无法解析出文本,放置操作没有实际效果
解决办法
方案1:扩展数据解析逻辑,兼容两种数据类型
修改CustomDropDelegate的performDrop方法,同时支持直接获取NSString和Data转String的情况:
struct CustomDropDelegate: DropDelegate { @Binding var items: [String] func performDrop(info: DropInfo) -> Bool { guard let item = info.itemProviders(for: ["public.text"]).first else { return false } item.loadItem(forTypeIdentifier: "public.text", options: nil) { (data, error) in DispatchQueue.main.async { // 优先处理Mac Catalyst下的NSString情况 if let text = data as? NSString { self.items.append(text as String) } // 兼容iOS下的Data情况 else if let textData = data as? Data, let text = String(data: textData, encoding: .utf8) { self.items.append(text) } } } return true } }
方案2:拖拽时强制指定数据格式
在onDrag闭包中,强制让NSItemProvider以Data形式提供数据,统一iOS和Mac Catalyst的处理逻辑:
.onDrag { let itemProvider = NSItemProvider(object: item as NSString) // 注册Data格式的表示,确保跨平台一致 itemProvider.registerDataRepresentation(forTypeIdentifier: "public.text", visibility: .all) { completion in completion(item.data(using: .utf8), nil) return nil } return itemProvider }
这两种方案都能解决Mac Catalyst下放置操作失效的问题,可根据需求选择其中一种。
内容的提问来源于stack exchange,提问作者János
相关产品推荐
相关产品推荐

