SwiftUI中如何用Rune模型UUID更新拖拽视图UUID变量
SwiftUI拖拽功能实现问题解决方案
问题描述
我是SwiftUI新手,不确定能不能实现这个需求:用一款依赖UUID识别拖拽项的Swift拖拽包,实现元素拖拽到指定区域。我通过Rune模型(代码如下)从JSON加载数据,用LazyVGrid展示多个实例,每个实例自带runeid(UUID)。我需要把选中实例的runeid赋值给runeofday变量,传入DragView的id参数,这样就能在drop zone捕获拖拽项,用来后续填充数据(比如卡片翻转)。但试了多种变量类型,这个UUID变量还是没法更新。如果有不用这个包的更好方案也可以接受。
相关代码
Rune模型代码
// MARK: - Rune MODEL struct Rune: Codable, Identifiable, Comparable { static func < (lhs: Rune, rhs: Rune) -> Bool { lhs.title < rhs.title } let runeid = UUID() var id: Int var title: String var headline: String var image: String var pronunciation: String var sound: String var aett: String var god: String var knownas: [String] var keywords: [String] var translation: String var magick: [String] var gallery: [String] var meanings: [String] var runelore: [String] var poeticedda: [String] }
LazyVGrid展示代码
LazyVGrid(columns: columns, spacing: 5) { ForEach(runes) { rune in RuneFrontView(rune: rune, width: width, height: height, degree: $frontDegree) RuneBackView(rune: rune, width: width, height: height, degree: $backDegree) switch rune.id { case 1: Text("rune 1") // runeofday = rune.runeid case 2: Text("rune 2") // runeofday = rune.runeid case 3: Text("rune 3") // runeofday = rune.runeid case 4: Text("rune 4") // runeofday = rune.runeid case 5: Text("rune 5") // runeofday = rune.runeid case 6: Text("rune 6") // runeofday = rune.runeid default: Text("rune default") } //:END OF SWITCH }.onTapGesture { flipCard () }//: END OF ON TAP }//: END OF LAZY V GRID
DragView代码
DragView(id: runeofday) { dragInfo in Text(dragInfo.isDragging ? "Im being dragged" : "Drag me 1") .padding() .background{ Color.mint } //:END OF BACK GROUND }
问题排查与修复(第三方包方案)
- 确保状态变量类型正确:
runeofday必须是可绑定的状态变量,用@State或@Binding声明:
@State private var runeofday: UUID? = nil
- 修正Tap事件绑定范围:当前
onTapGesture加在ForEach外层,点击任意网格项都会触发同一个事件,无法定位具体rune。需要把onTapGesture移到每个rune的视图容器内:
ForEach(runes) { rune in VStack { RuneFrontView(rune: rune, width: width, height: height, degree: $frontDegree) RuneBackView(rune: rune, width: width, height: height, degree: $backDegree) switch rune.id { // 你的switch代码 } } .onTapGesture { runeofday = rune.runeid flipCard() } }
原生SwiftUI拖拽方案(推荐)
无需依赖第三方包,用SwiftUI原生Drag&Drop实现更稳定:
1. 添加拖拽源到每个Rune项
ForEach(runes) { rune in VStack { RuneFrontView(rune: rune, width: width, height: height, degree: $frontDegree) RuneBackView(rune: rune, width: width, height: height, degree: $backDegree) switch rune.id { // 你的switch代码 } } .onDrag { // 将runeid转为字符串作为拖拽数据 NSItemProvider(object: rune.runeid.uuidString as NSString) } .onTapGesture { flipCard() } }
2. 创建投放区域
@State private var selectedRuneId: UUID? = nil VStack { Text(selectedRuneId != nil ? "已选中符文ID: \(selectedRuneId!.uuidString)" : "拖拽符文到这里") .padding() .background(Color.mint) } .onDrop(of: [.text], delegate: DropZoneDelegate(selectedRuneId: $selectedRuneId))
3. 实现DropDelegate处理投放逻辑
class DropZoneDelegate: DropDelegate { @Binding var selectedRuneId: UUID? init(selectedRuneId: Binding<UUID?>) { _selectedRuneId = selectedRuneId } func performDrop(info: DropInfo) -> Bool { guard let item = info.itemProviders(for: [.text]).first else { return false } item.loadObject(ofClass: NSString.self) { [weak self] value, error in guard let uuidString = value as? String, let uuid = UUID(uuidString: uuidString) else { return } DispatchQueue.main.async { self?.selectedRuneId = uuid // 在这里触发卡片翻转等后续操作 } } return true } }
内容的提问来源于stack exchange,提问作者brandon aho
相关产品推荐
相关产品推荐

