如何在 SwiftUI 中更新单个子视图? [英] How to update a single child view in SwiftUI?

查看:35
本文介绍了如何在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆