SwiftUI中数组内对象拖拽时视图不更新问题求助
SwiftUI拖拽视图不更新:ObservableObject数组的观察问题
问题现象
编写的SwiftUI代码可正常编译并展示数组内容,但拖拽对象时,终端打印显示tOffset变量持续更新,视图却未同步刷新。怀疑是属性包装器使用不当,@ObservedObject对数组内的对象变化未正确响应。
核心原因
- 数组的Published通知机制:
tokenArray中的@Published var tokens仅在数组本身的引用发生变化(如添加、删除元素)时才会触发视图更新。而数组内的varToken/expToken实例是引用类型,其内部@Published属性的变化不会触发数组的Published通知,因此父视图ViewDemo2无法感知到这些内部变化。 - 未跟踪子对象的变化:原视图中直接遍历
tokens数组并使用其中的对象,但未对每个Token子类实例单独进行观察,导致这些实例内部的属性更新无法传递到视图刷新流程中。
解决方案
将每个Token对应的视图拆分为独立的子视图,并在子视图中使用@ObservedObject观察对应的Token实例,确保实例内部的@Published属性变化能触发视图刷新。
修改后的完整代码
类声明部分(保持不变)
class Token: Identifiable, ObservableObject{ var id: UUID var name: String var scale: CGFloat @Published var sOffset: CGSize @Published var cOffset: CGSize @Published var tOffset: CGSize init(n: String) { id = UUID() name = n scale = 2.0 sOffset = .zero cOffset = .zero tOffset = .zero updateTOffset() } public func updateTOffset() { tOffset.height = sOffset.height + cOffset.height tOffset.width = sOffset.width + cOffset.width print("Updated T Offset , x: \(tOffset.width), y:\(tOffset.height) ") } } class varToken: Token { var exp: expToken? init(name: String, exp: expToken?) { super.init(n: name) self.exp = exp } } class expToken: Token { @Published var bOffset: CGSize = .zero init(name: String) { super.init(n: name) sOffset.height = -10 scale = 1.0 updateTOffset() } } class tokenArray: Identifiable, ObservableObject { var id: UUID = UUID() @Published var tokens: [varToken] = [varToken(name: "1 +", exp: nil), varToken(name: "x", exp: expToken(name: "2"))] }
视图部分(拆分后)
struct ViewDemo2: View { @ObservedObject var t: tokenArray = tokenArray() var body: some View { HStack(alignment: .bottom) { ForEach(t.tokens) { token in VarTokenView(token: token) } } } } // 封装varToken对应的视图 struct VarTokenView: View { @ObservedObject var token: varToken var body: some View { HStack(alignment: .bottom) { Text(token.name) .scaleEffect(token.scale, anchor: .center) .offset(token.tOffset) .padding(.leading, 10) // 处理expToken视图 if let exp = token.exp { ExpTokenView(exp: exp) } } } } // 封装expToken对应的视图 struct ExpTokenView: View { @ObservedObject var exp: expToken var body: some View { Text(exp.name) .scaleEffect(exp.scale) .offset(exp.tOffset) .gesture( DragGesture() .onChanged { value in withAnimation(.spring()) { exp.cOffset = value.translation exp.updateTOffset() } } .onEnded { value in withAnimation(.spring()) { exp.cOffset = .zero exp.updateTOffset() } } ) } }
说明
- 拆分后的子视图通过
@ObservedObject绑定对应的Token实例,当实例内部的@Published属性(如cOffset、tOffset)变化时,子视图会立即收到通知并刷新,解决了原视图无法感知内部变化的问题。 - 这种拆分也符合SwiftUI的视图组合设计原则,让代码结构更清晰,职责更单一。
内容的提问来源于stack exchange,提问作者Simeon Shaffar
相关产品推荐
相关产品推荐

