首页 > 解决方案 > SwiftUI 将 View 存储为变量,同时传递一些绑定

问题描述

我想将 aView作为变量存储以供以后使用,同时传递View一些Bindings. 这是我尝试过的:

struct Parent: View {
    @State var title: String? = ""
    var child: Child!

    init() {
        self.child = Child(title: self.$title)
    }

    var body: some View {
        VStack {
            child
            //...
            Button(action: {
                self.child.f()    
            }) {
                //...
            }
        }
    }
}

struct Child: View {
    @Binding var title: String?

    func f() {
        // complex work from which results a string
        self.title = <that string>
    }

    var body: some View {
        // ...
    }
}

它可以正确编译View并按预期显示,但是当从Binding父级传递的子级更新时,变量永远不会更新。你甚至可以做这样的事情(从孩子):

self.title = "something"
print(self.title) // prints the previous value, in this case nil

我不知道这是否是一个错误,但直接在body属性中初始化孩子就可以了。但是,我需要那个孩子作为一个属性来访问它的方法。

标签: swiftswiftui

解决方案


这与 SwiftUI 框架的设计背道而驰。您不应该有任何持久视图来调用方法。相反,视图会根据需要创建和显示,以响应应用程序的状态变化。

将您的数据封装在ObservableObject模型中,并实现您需要在该模型上调用的任何方法。

更新

可以在 中定义这样的函数Child,但您应该只在Childstruct 定义中调用它。例如,如果您的子视图包含一个按钮,则该按钮可以调用子视图的实例方法。例如,

struct Parent: View {
    @State private var number = 1

    var body: some View {
        VStack {
            Text("\(number)")
            Child(number: $number)
        }
    }
}

struct Child: View {
    @Binding var number: Int

    func double() {
        number *= 2
    }

    var body: some View {
        HStack {
            Button(action: {
                self.double()
            }) {
                Text("Double")
            }
        }
    }
}

但是您不会尝试double()从子结构外部调用。如果您想要一个可以全局调用的函数,请将其放入数据模型中。如果函数调用正在发出网络请求,则尤其如此,因为模型将停留在您的子视图之外,即使由于布局更改而重新创建它也是如此。

class NumberModel: ObservableObject {
    @Published var number = 1

    func double() {
        number *= 2
    }
}

struct Parent: View {
    @ObservedObject var model = NumberModel()

    var body: some View {
        VStack {
            Text("\(model.number)")

            Button(action: {
                self.model.double()
            }) {
                Text("Double from Parent")
            }

            Child(model: model)
        }
    }
}

struct Child: View {
    @ObservedObject var model: NumberModel

    var body: some View {
        HStack {
            Button(action: {
                self.model.double()
            }) {
                Text("Double from Child")
            }
        }
    }
}

推荐阅读