SwiftUI问题:变量更新后绘制光伏板的Path未自动重绘
问题解决:SwiftUI中Shape未随ObservedObject更新而刷新
问题根源
drawPanels是值类型的Shape,你在其中使用@ObservedObject监听variables变化,但值类型内的@ObservedObject无法触发SwiftUI重新调用path(in:)方法。尽管variables数值已更新,且path方法能打印出新值,但SwiftUI未检测到Shape实例的变化,因此不会重新绘制路径。
解决方法
方法1:为Shape添加标识ID
在displayPanelSpacing视图中,给drawPanels绑定.id()修饰符,关联到variables.tiltAngle:
drawPanels(variables: variables) .id(variables.tiltAngle) // 角度变化时强制重建Shape实例 .stroke(changeLine ? Color(.red) : .gray, lineWidth: 3.0) .frame(width: (GlobalVariables.screenWidth - 64), height: 150) .padding(.leading, 16) .padding(.trailing, 16) .scaleEffect(changeLine ? 0.5 : 1.0) .overlay(DrawSun(radius: 25).foregroundColor(.orange))
当tiltAngle更新时,SwiftUI会判定这是新的drawPanels实例,从而重新执行path(in:)生成新路径。
方法2:让Shape遵循Equatable
若Variables类实现了Equatable,可让drawPanels也遵循该协议,SwiftUI会自动检测属性变化并刷新:
struct drawPanels: Shape, Equatable { static func == (lhs: drawPanels, rhs: drawPanels) -> Bool { // 比较影响路径生成的核心属性,这里用倾斜角度即可 return lhs.variables.tiltAngle == rhs.variables.tiltAngle } let variables: Variables // 改为普通let属性,无需@ObservedObject func path(in rect: CGRect) -> Path { // 原有路径生成代码保持不变 let result = variables.ed() let edEndX = result.endX let edEndY = result.endY let baselineY = rect.maxY let baselineXOffset = 10 let panelY = Int(rect.maxY) - edEndY let panel1X = baselineXOffset + edEndX let panel2X = baselineXOffset + Int(rect.midX) + edEndX var path = Path() path.move(to: CGPoint(x: rect.minX + 10, y: baselineY)) path.addLine(to: CGPoint(x: panel1X, y: panelY)) path.move(to: CGPoint(x: rect.midX + 10, y: baselineY)) path.addLine(to: CGPoint(x: panel2X, y: panelY)) return path } }
修改后,SwiftUI会自动对比前后drawPanels实例的属性,当variables.tiltAngle变化时重新计算路径。
额外编码规范建议
- Swift中结构体/视图命名应遵循大驼峰式,建议把
drawPanels改为DrawPanels,displayPanelSpacing改为DisplayPanelSpacing。 - 调试用的打印语句建议在调试完成后移除,避免不必要的性能开销。
内容的提问来源于stack exchange,提问作者Edward Hasted
相关产品推荐
相关产品推荐

