我在玩@resultBuilder
,做了一个简单的结果构建器,叫做SumBuilder
,它接受一堆整数,然后把它们加起来。
@resultBuilder
struct SumBuilder {
static func buildBlock(_ components: Int...) -> Int {
components.reduce(0, +)
}
}
因为前几天我也在玩形状,所以我想创建一个自定义形状,它可以在实现中使用这个新的结果生成器。自定义形状只是从容器的原点到指定的点画一条线。
struct CustomShape: Shape {
@SumBuilder let sum: () -> Int
func path(in rect: CGRect) -> Path {
Path { path in
path.move(to: .zero)
path.addLine(to: CGPoint(x: sum(), y: sum()))
}
}
}
当我把sum
连接到ContentView
中的@State
变量时,它运行得很好,但是当我用.onAppear()
修改sum
时,sum
的值会在幕后发生变化,但是View
并没有相应地更新:
struct ContentView: View {
@State private var distance = 0
var body: some View {
VStack {
Button("Increase distance") {
distance += 100
}
CustomShape { distance }
.stroke()
.onAppear { distance = 100 } // << Updates distance, but the View still doesn't show
// the line until I press the Button to make distance = 200
}
}
}
我试着把.onAppear()
移到Text
,以为.onAppear()
没有被调用,因为CustomShape
最初是一个点,但这没有改变任何东西,更奇怪的是,当我把CustomShape
转换成一个普通的View
时,.onAppear()
按预期工作。
有没有人知道如何制作一个Shape
,即使使用.onAppear()
改变了一个值,也能使用@resultBuilder
更新?如果你能以任何形式提供帮助,我将非常感激。
先谢了!
2条答案
按热度按时间mxg2im7a1#
正如我提到的,我只是尝试了你的代码,但使用了一个ViewModel,它的工作与预期的一样。在生产中,你可能想使用输入-输出-模式,但这是最少的代码量来解释我使用ViewModel的意思。
6ie5vjzr2#
在SwiftUI中,
.onAppear()
修饰符用于在视图出现在屏幕上时执行某些操作。但是,此修饰符不会触发视图的重新呈现,因此在.onAppear()闭包中所做的任何更改都不会反映在视图的外观中。这也适用于使用@resultBuilder的形状。如果形状是使用@resultBuilder创建的,并且您在
.onAppear()
闭包中对其进行了更改,则这些更改在视图中不可见。要更新使用@resultBuilder的形状,您需要使用.onChange()
或.onReceive()
而不是.onAppear()
来更新形状,这将触发视图重新呈现。