SwiftUI-自定义绑定

2021-07-21  本文已影响0人  rayChow

当我们使用一个Picker或者TextField之类的控件时,我们通常使用@State绑定属性。但这只对简单的属性有用,如果我们需要运行一些逻辑来计算当前值,该怎么去处理呢?那就是自定义绑定。
首先,我们可以看一下绑定最简单的形式:

struct ContentView: View {
    @State private var selection = 0
    var body: some View {
        let binding = Binding(
            get: {self.selection},
            set: {self.selection = $0}
        )
        Picker("选择", selection: binding) {
            ForEach(0..<4) { index in
                Text("item\(index)")
            }
        }
        .pickerStyle(DefaultPickerStyle())
    }
}

可以看出,改绑定实际上只传递值,它本身不存储或计算任何数据,而只充当我们UI层和正在操作的底层状态值之间的垫片。
值得注意的是,选择器现在使用的是selection: binding,不需要$绑定符来修饰,因为它已经是一个双向绑定了。

其次,我们可以使用高级的自定义绑定,不仅仅是传递单个值。例如,假设我们有一个带有三个切换开关的表单:用户是否同意条款和条件、同意隐私政策以及同意接收有关运输的电子邮件。
我们可以将其表示为三个@State属性:

@State var agreedToTerms = false
@State var agreedToPrivacyPolicy = false
@State var agreedToEmails = false

尽管可以手动切换它们,但我们可以使用自定义绑定一次性完成所有操作。如果这三个布尔值都为真,则此绑定将为真,一旦,则会更新它们,如下所示:

let agreedToAll = Binding(
    get: {
        self.agreedToTerms && self.agreedToPrivacyPolicy && self.agreedToEmails
    },
    set: {
        self.agreedToTerms = $0
        self.agreedToPrivacyPolicy = $0
        self.agreedToEmails = $0
    }
)

现在我们可以创建四个切换开关:三个用于单个布尔值,一个控制其他三个同时同意或不同意:
struct ContentView: View {
    @State var agreedToTerms = false
    @State var agreedToPrivacyPolicy = false
    @State var agreedToEmails = false

    var body: some View {
        let agreedToAll = Binding<Bool>(
            get: {
                self.agreedToTerms && self.agreedToPrivacyPolicy && self.agreedToEmails
            },
            set: {
                self.agreedToTerms = $0
                self.agreedToPrivacyPolicy = $0
                self.agreedToEmails = $0
            }
        )

        return VStack {
            Toggle(isOn: $agreedToTerms) {
                Text("Agree to terms")
            }

            Toggle(isOn: $agreedToPrivacyPolicy) {
                Text("Agree to privacy policy")
            }

            Toggle(isOn: $agreedToEmails) {
                Text("Agree to receive shipping emails")
            }

            Toggle(isOn: agreedToAll) {
                Text("Agree to all")
            }
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读