如何在 SwiftUI 中更新单个子视图?

Enz*_*rro 6 swiftui

我正在尝试在子视图和父视图之间建立 SwiftUI 连接。通过单击任何子视图,我只想重绘已被点击的视图,而不是整个父视图。

下面的当前实现不允许您在单击时重绘视图,因为它具有派生值。

我通过将BindableObject协议添加到 尝试了不同的场景CustomColor,但没有成功。

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)
        })
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的用户界面

Enz*_*rro 1

我想我已经找到了解决方案。第一个问题是我通过重复相同的元素而不是添加独立的元素来初始化颜色数组。

更重要的是,CustomColor它本身应该具有BindableObject一致性,而不是模型(我们不改变颜色数组,我们改变每种颜色)。最后,我们不需要将对象包装在ForEach元素中(这样就失去了可重用性),而是将它们放在List元素中。

通过此实现,只有已更改的视图才会被重绘,而不是整个集合。

这是代码:

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)
        })
    }

}

Run Code Online (Sandbox Code Playgroud)