在下面的SwiftUI代码中,我有三个主要组件:
TestView
-保存TestClass
实例,显示MyShape
,并随时更新TestClass
实例的计数。
TestClass
-一个用于存储count
的简单类,该类在更改时发布。
MyShape
-一个简单的形状,其位置(应该(随着TestView
中TestClass
实例的计数的变化而变化。
问题是MyShape
的位置在计数更新时不会更改。
我知道计数正在更新,因为如果我在文本视图中显示计数,它会在点击时更改,所以当计数更改时,形状不会在计数更改时更新。为什么形状没有更新/为什么发布者没有达到形状?
struct TestView: View {
@ObservedObject var counter: TestClass = TestClass()
var body: some View {
ZStack {
MyShape(counter: counter)
.stroke(Color.red, lineWidth: 50)
.onTapGesture {
counter.count += 1
}
}
}
}
class TestClass: ObservableObject {
@Published var count = 0
}
struct MyShape: Shape {
var counter: TestClass
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: counter.count, y: counter.count))
return path
}
}
SwiftUI仅在View
或Shape
的属性更改时更新。
目前,MyShape
在第一次渲染后从未更改其属性,因为TestClass
是一个引用类型(即本例中的class
(——SwiftUI只看到属性是相同的,即使TestClass
上的一个内部属性发生了更改,也不必渲染新版本的MyShape
。
在View
中,我们可以使用@ObservedObject
属性包装器,以便View
知道在ObservableObject
的@Published
属性更改时进行更新(就像在TestView
中所做的那样(,但该包装器在Shape
中不可用。
这里最简单的解决方案是通过count
而不是counter
。count
是Int
(即值类型(,这意味着无论何时更改,SwiftUI都会知道更新Shape
:
struct TestView: View {
@ObservedObject var counter: TestClass = TestClass()
var body: some View {
ZStack {
MyShape(count: counter.count)
.stroke(Color.red, lineWidth: 50)
.onTapGesture {
counter.count += 1
}
}
}
}
class TestClass: ObservableObject {
@Published var count = 10
}
struct MyShape: Shape {
var count: Int
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: count, y: count))
return path
}
}
另一种可能更适合SwiftUI原则的解决方案是将您的模型更改为struct
。然后,模型可以传递给Shape
,由于它是一个值类型,Shape
将更新。当然,这是假设您的真实世界模型更复杂,并且具有Shape
所需的不止一个属性——否则,保留仅公开其所需内容的原始解决方案(即Int
(可能是更好的解决方案。
struct TestView: View {
@State var counter: TestStruct = TestStruct()
var body: some View {
ZStack {
MyShape(counter: counter)
.stroke(Color.red, lineWidth: 50)
.onTapGesture {
counter.count += 1
}
}
}
}
struct TestStruct {
var count = 10
}
struct MyShape: Shape {
var counter: TestStruct
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: counter.count, y: counter.count))
return path
}
}
注意:我更新了初始count
,以便在开始时更容易点击视图