Hacking with iOS: SwiftUI Edition

SwiftUI:创建自定义绑定

2020-06-02  本文已影响0人  韦弦Zhy

\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}

{\Large \mathbf{Instafilter}}

由于SwiftUI将绑定更新发送到属性包装器的方式,分配与属性包装器一起使用的属性观察器将无法正常工作,这意味着即使模糊半径发生变化,此类代码也不会打印任何内容:

struct ContentView: View {
    @State private var blurAmount: CGFloat = 0 {
        didSet {
            print("New value is \(blurAmount)")
        }
    }

    var body: some View {
        VStack {
            Text("Hello, World!")
                .blur(radius: blurAmount)

            Slider(value: $blurAmount, in: 0...20)
        }
    }
}

要解决此问题,我们需要创建一个自定义绑定——我们需要直接使用Binding结构体,该结构体在读取或写入值时允许我们提供我们自己的代码来运行。

在我们的代码中,我们希望Binding在读取时返回blurAmount的值,但是在写入时,我们想要更改blurAmount的值并打印该新值,以便我们可以看到它已更改。不管我们是在读取还是在写入,我们都在谈论读取了blurAmount属性的内容,而Swift不允许我们创建读取其他属性的属性,因为我们尝试读取的属性可能尚未创建。

因此,将所有这些放在一起,我们需要创建一个自定义的Binding结构体,该结构充当blurAmount的传递对象,但是当我们设置该值时,我们还希望打印一条消息。另外,我们也不得将其存储为视图的属性,因为不允许从另一个属性读取一个属性。

所以,我们需要将此代码放入视图的body属性中,如下所示:

struct ContentView: View {
    @State private var blurAmount: CGFloat = 0

    var body: some View {
        let blur = Binding<CGFloat>(
            get: {
                self.blurAmount
            },
            set: {
                self.blurAmount = $0
                print("New value is \(self.blurAmount)")
            }
        )

        return VStack {
            Text("Hello, World!")
                .blur(radius: blurAmount)

            Slider(value: blur, in: 0...20)
        }
    }
}

在进入绑定本身之前,请注意其他内容如何保持不变:我们仍然使用@State private var声明blurAmount属性,并且仍然使用.blur(radius: blurAmount)作为文本视图的修饰符。

更改的一个地方是我们在滑块中声明绑定的方式:我们不在使用$blurAmount,而是直接使用blur。这是因为使用美元符号可以使我们从某个状态属性获得双向绑定,但是现在我们已经直接创建了绑定,因此不再需要它。

好的,现在让我们来看一下绑定本身。您应该可以从我们的使用方式中看出来,Binding的基本初始化器如下所示:

init(get: @escaping () -> Value, set: @escaping (Value) -> Void)

您可以通过按 Cmd + Shift + O 并在已生成的SwiftUI界面中查找“Binding”来找到它。详细地讲,它告诉我们初始化程序采用两个闭包:一个不带参数并返回值的getter,和一个带值但不返回任何值的setter。绑定使用泛型,因此Value实际上是我们存储在内部的所有内容的占位符——对于我们的模糊绑定而言是CGFloatgetset闭包都标记为@escaping,这意味着Binding结构体存储它们供以后使用。

这意味着您可以在这些闭包内做任何您想做的事情:可以调用方法,运行算法以找出要使用的正确值,甚至只是使用随机值——没关系,只要您从get返回值。因此,如果要确保每次更改值时都更新UserDefaults,则Bindingset闭包是完美的。

译自 Creating custom bindings in SwiftUI

上一篇下一篇

猜你喜欢

热点阅读