SwiftUI:使用 AnimatablePair 对复杂形状进行动画处理

SwiftUI使用animatableData属性让我们对形状的变化进行动画处理,但是当我们希望对两个,三个,四个或更多个属性进行动画处理时会发生什么呢?animatableData是一个属性,这意味着它必须始终是一个值,但是我们要决定它是什么类型的值:它可以是单个CGFloat,也可以是包含在称为AnimatablePair的特殊包装中的两个值。

为了尝试这一点,让我们看一个新的叫做Checkerboard的形状,它必须以一定数量的行和列创建:

struct Checkerboard: Shape {
    var rows: Int
    var columns: Int

    func path(in rect: CGRect) -> Path {
        var path = Path()

        // 计算每行/列需要多大
        let rowSize = rect.height / CGFloat(rows)
        let columnSize = rect.width / CGFloat(columns)

        // 循环遍历所有行和列,从而使交替的正方形变为彩色
        for row in 0..

现在,我们可以使用一些状态属性在SwiftUI视图中创建一个4x4棋盘格,我们可以使用点击手势来更改这些属性:

struct ContentView: View {
    @State private var rows = 4
    @State private var columns = 4

    var body: some View {
        Checkerboard(rows: rows, columns: columns)
            .onTapGesture {
                withAnimation(.linear(duration: 3)) {
                    self.rows = 8
                    self.columns = 16
                }
            }
    }
}

运行该命令后,您应该可以点击黑色正方形以查看棋盘格从4x4跳到8x16,并且没有动画,即使更改位于withAnimation()块内。

与更简单的形状一样,此处的解决方案是实现animatableData属性,该属性将在动画进行时设置中间值。不过,这里有两个问题:

  1. 我们有两个要设置动画的属性,而不是一个。
  2. 我们的rowcolumn属性是整数,SwiftUI不能插入整数。

为了解决第一个问题,我们将使用一种称为AnimatablePair的新类型。顾名思义,它包含一对可动画设置的值,并且由于两个值都可以设置动画,因此AnimatablePair本身可以设置动画。我们可以使用.first.second从对中读取单个值。

为了解决第二个问题,我们将要做一些类型转换:我们可以仅使用Int(someDouble)Double转换为Int,而使用Double(someInt)将其转换为Int

因此,要使我们的棋盘动画化行数和列数的变化,请添加以下属性:

public var animatableData: AnimatablePair {
    get {
       AnimatablePair(Double(rows), Double(columns))
    }

    set {
        self.rows = Int(newValue.first)
        self.columns = Int(newValue.second)
    }
}

现在,当您运行该应用程序时,您应该发现更改进行得很顺利——或考虑到我们将数字四舍五入为整数所期望的平滑变化。

当然,下一个问题是:我们如何为三个属性设置动画?还是四个?

为了回答这个问题,让我向您展示SwiftUI EdgeInsets类型的animatableData属性:

AnimatablePair>>

是的,它们使用三个独立的动画对,然后使用诸如newValue.second.second.first之类的代码对其进行设置。

我不会断言这是最优雅的解决方案,但我希望您能理解它存在的原因:因为SwiftUI可以读取和写入形状的可动画显示的数据,而无论该数据是什么或意味着什么,它都不会在动画制作过程中,无需每秒60甚至120次重新调用视图的body属性——只需更改实际更改的部分即可。

译自 Animating complex shapes with AnimatablePair

SwiftUI:使用 animatableData 给形状设置动画 Hacking with iOS: SwiftUI Edition 使用SwiftUI创建万花尺

赏我一个赞吧~~~

你可能感兴趣的:(SwiftUI:使用 AnimatablePair 对复杂形状进行动画处理)