我有以下观点:
struct SpriteView: View {
@Binding var name: String
@State var sprite: Image = Image(systemName: "exclamationmark")
var body: some View {
VStack{
sprite
}
.onAppear(perform: loadSprite)
}
func loadSprite() {
// async function
getSpriteFromNetwork(self.name){ result in
switch result {
// async callback
case .success(newSprite):
self.sprite = newSprite
}
}
}
我要发生的事情非常简单:用户在文本字段中(从父视图中)修改name
,然后使用新的sprite重新加载SpriteView
。但是上面的视图不起作用,因为当用新名称重新加载视图时,不会再次调用loadSprite
(onAppear
仅在首次加载视图时触发)。我也不能将loadSprite
放在视图本身中(并返回一个图像),因为它会导致无限循环。
有一个Beta函数onChange
正是我要寻找的功能,但仅在Xcode的Beta版本中。由于Combine是异步回调的全部,并且SwiftUI和Combine应该可以很好地结合使用,因此我认为这种行为很难实现,但是我遇到了很多麻烦。
答案 0 :(得分:0)
我并不特别喜欢这种解决方案,因为它需要创建一个新的ObservableObject
,但这是我最终要这样做的方式:
class SpriteLoader: ObservableObject {
@Published var sprite: Image = Image(systemName: "exclamationmark")
func loadSprite(name: String) {
// async function
self.sprite = Image(systemName: "arrow.right")
}
}
struct ParentView: View {
@State var name: String
@State var spriteLoader = SpriteLoader()
var body: some View {
SpriteView(spriteLoader: spriteLoader)
TextField(name, text: $name, onCommit: {
spriteLoader.loadSprite(name: name)
})
}
}
struct SpriteView: View {
@ObservedObject var spriteLoader: SpriteLoader
var body: some View {
VStack{
spriteLoader.sprite
}
}
}
旧答案:
我认为做到这一点的最佳方法如下:
父视图:
struct ParentView: View {
@State var name: String
@State spriteView = SpriteView()
var body: some View {
spriteView
TextField(value: $name, onCommit: {
spriteView.loadSprite(name)
})
}
然后,sprite视图甚至不需要@Binding name
成员。