SwiftUI:使用 @Binding 创建自定义组件

您已经了解了SwiftUI的@State属性包装器如何使我们处理本地值类型,以及@ObservedObject如何使我们处理可共享的引用类型。好吧,还有第三个选项@Binding,它使我们可以将一个视图的@State属性连接到一些基础模型数据。

考虑一下:创建切换开关时,我们发送某种可以更改的布尔属性,如下所示:

@State private var rememberMe = false

var body: some View {
    Toggle(isOn: $rememberMe) {
        Text("Remember Me")
    }
}

因此,切换开关需要在用户与其交互时更改我们的布尔值,但是它如何记住应更改的值?

这就是@Binding出现的地方:它使我们可以在视图中创建一个可变值,该值实际上指向其他位置的其他值。在此处的Toggle,开关会将自己的本地绑定更改为布尔值,但在幕后,它实际上是在操作视图中的@State属性。

这使得@Binding对于每当您要创建自定义用户界面组件时都非常重要。UI组件与其他组件一样,其核心就是SwiftUI视图,但是@Binding是使它们与众不同的地方:尽管它们可能具有其本地@State属性,但它们还公开了@Binding属性,使它们直接与其他视图交互。

为了演示这一点,我们将创建一种新的按钮:当按下该按钮时该按钮保持按下状态。我们的基本实现将是您以前见过的所有事情:带有填充的按钮,背景的线性渐变,胶囊形状等等,现在将其添加到 ContentView.swift:

struct PushButton: View {
    let title: String
    @State var isOn: Bool

    var onColors = [Color.red, Color.yellow]
    var offColors = [Color(white: 0.6), Color(white: 0.4)]

    var body: some View {
        Button(title) {
            self.isOn.toggle()
        }
        .padding()
        .background(LinearGradient(gradient: Gradient(colors: isOn ? onColors : offColors), startPoint: .top, endPoint: .bottom))
        .foregroundColor(.white)
        .clipShape(Capsule())
        .shadow(radius: isOn ? 0 : 5)
    }
}

唯一稍微的令人兴奋的事情是,我使用了两种渐变颜色的属性,因此可以通过创建按钮的方式对其进行自定义。

现在,我们可以在主用户界面中创建其中一个按钮,如下所示:

struct ContentView: View {
    @State private var rememberMe = false

    var body: some View {
        VStack {
            PushButton(title: "Remember Me", isOn: rememberMe)
            Text(rememberMe ? "On" : "Off")
        }
    }
}

该按钮下方有一个文本视图,因此我们可以跟踪按钮的状态——尝试运行您的代码并查看其工作方式。

您会发现,点击按钮确实会影响它的显示方式,但是我们的文本视图并不能反映出这种变化——它始终显示为“Off”。显然,某些事情正在发生变化,因为按下按钮时其外观会发生变化,但这种变化不会反映在ContentView中。

这里发生的事情是我们定义了一种单向数据流:ContentView有它的RememberMe布尔值,它用于创建一个PushButton ——该按钮具有由ContentView提供的初始值。但是,一旦创建了按钮,它将接管对值的控制:它将按钮内部的isOn属性在内部true或false之间切换至按钮,但不会将更改重新传递给ContentView

这是一个问题,因为我们现在有两个事实来源:ContentView存储一个值,而PushButton存储另一个值。幸运的是,这就是@Binding的主场:它允许我们在PushButton和使用它的对象之间创建双向连接,以便当一个值更改时,另一个也是如此。

要切换到@Binding,我们只需要进行两项更改。首先,在PushButton中将其isOn属性更改为:

@Binding var isOn: Bool

其次,在ContentView中更改我们创建按钮的方式:

PushButton(title: "Remember Me", isOn: $rememberMe)

这会在RememberMe之前添加一个美元符号——我们传递的是绑定本身,而不是绑定内部的布尔值。

现在再次运行代码,您会发现一切都按预期进行:切换按钮现在也可以正确更新文本视图。

这是@Binding的强大功能:就按钮而言,它只是切换一个布尔值——它不知道有其他东西正在监视该布尔值并根据更改进行操作。

Creating a custom component with @Binding

纸杯蛋糕项目——挑战 Hacking with iOS: SwiftUI Edition 使用 size classes 时通过 AnyView 实现类型擦除

赏我一个赞吧~~~

你可能感兴趣的:(SwiftUI:使用 @Binding 创建自定义组件)