如何在 SwiftUI 中更新单个子视图? [英] How to update a single child view in SwiftUI?
问题描述
我正在尝试在子视图和父视图之间建立 SwiftUI 连接.通过单击任何子视图,我只想重绘已被点击的视图,而不是整个父视图.
I am trying to establish a SwiftUI connection between the child view and the parent view. By clicking on any child view, I want to redraw only the view that has been tapped, not the entire parent view.
下面的当前实现不允许您在单击时重新绘制视图,因为它具有派生值.
The current implementation below does not allow you to redraw the view when you click on it, as it has a derived value.
我尝试了不同的场景,将 BindableObject
协议添加到 CustomColor
,但没有成功.
I tried different scenarios by adding the BindableObject
protocol to CustomColor
, but without success.
class CustomColor: Identifiable {
let id = UUID()
var color: Color
init(color: Color) {
self.color = color
}
func change(to color: Color) {
self.color = color
}
}
class ColorStore: BindableObject {
var colors: [CustomColor] = [] {
didSet {
didChange.send(self)
}
}
var didChange = PassthroughSubject<ColorStore, Never>()
init() {
self.colors = Array.init(repeating: CustomColor(color: .red), count: 10)
}
}
struct ContentView: View {
@EnvironmentObject var colorStore: ColorStore
var body: some View {
NavigationView {
List {
ForEach(colorStore.colors) { color in
ColorShape(color: color)
}
}.navigationBarTitle(Text("Colors"))
}
}
}
struct ColorShape: View {
var color: CustomColor
var body: some View {
Button(action:
{ self.color.change(to: .blue) }
, label: {
ShapeView(shape: Circle(), style: color.color)
})
}
}
推荐答案
我想我已经找到了解决方案.第一个问题是我通过重复相同的元素而不是添加独立的元素来初始化颜色数组.
I think I've found a solution. The first problem was that I initialized array of colors by repeating the same element instead of adding independent ones.
更重要的是 CustomColor
本身应该具有 BindableObject
一致性,而不是模型(我们不改变颜色数组,我们改变每种颜色).最后,我们不需要将对象包装在 ForEach 元素中(这样我们就失去了可重用性),而是将它们放在 List 元素中.
What is more CustomColor
itself should have BindableObject
conformance, not the model (we don't change the array of colors, we change each color).
Lastly, we don't need to wrap objects in ForEach element (we loose reusability that way), and instead we put them in List element.
使用此实现,只会重绘已更改的视图,而不是整个集合.
With this implementation, only the view that has been changed will be redrawn, not the entire collection.
代码如下:
class CustomColor: BindableObject, Identifiable {
var didChange = PassthroughSubject<CustomColor, Never>()
let id = UUID()
var color: Color {
didSet {
self.didChange.send(self)
}
}
init(color: Color) {
self.color = color
}
func change(toColor color: Color) {
self.color = color
}
}
class ColorStore {
var colors: [CustomColor] = []
init() {
(0...10).forEach { _ in colors.append(CustomColor(color: .red)) }
}
}
struct ContentView: View {
let colorStore: ColorStore
var body: some View {
NavigationView {
List(colorStore.colors) { color in
ColorShape(color: color)
}.navigationBarTitle(Text("Colors"))
}
}
}
struct ColorShape: View {
@ObjectBinding var color: CustomColor
var body: some View {
Button(action: { self.color.change(toColor: .blue) }, label: {
ShapeView(shape: Circle(), style: color.color)
})
}
}
这篇关于如何在 SwiftUI 中更新单个子视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!