SwiftUI:使用 animatableData 给形状设置动画

现在,我们涵盖了与绘图有关的各种任务,在项目6中,我们研究了动画,因此现在我想将这两件事放在一起。

首先,让我们构建一个自定义形状,以供示例使用——这是梯形形状的代码,梯形形状是具有直边且一对相对边平行的四边形:

struct Trapezoid: Shape {
    var insetAmount: CGFloat

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

        path.move(to: CGPoint(x: 0, y: rect.maxY))
        path.addLine(to: CGPoint(x: insetAmount, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: 0, y: rect.maxY))

        return path
   }
}

现在,我们可以在视图内部使用该视图,并为其插入量传递一些本地状态,以便我们可以在运行时修改该值:

struct ContentView: View {
    @State private var insetAmount: CGFloat = 50

    var body: some View {
        Trapezoid(insetAmount: insetAmount)
            .frame(width: 200, height: 100)
            .onTapGesture {
                self.insetAmount = CGFloat.random(in: 10...90)
            }
    }
}

每次点击梯形时,insetAmount都会设置为新值,从而导致形状被重绘。

如果我们可以动画化插图变化,那会不会很好?当然可以,尝试将onTapGesture()闭包更改为此:

.onTapGesture {
    withAnimation {
        self.insetAmount = CGFloat.random(in: 10...90)
    }
}

现在再次运行它,e……,没有任何改变。我们已经要求动画,但是它没有,要怎么办?

以前查看动画时,我要求您在body属性内添加对print()的调用,然后说过这样的话:

”你应该看到它输出了2.0,3.0,4.0等等。同时,该按钮可以平滑地上下缩放,而不仅仅是直接跳到缩放2、3和4。这里实际发生的情况是,SwiftUI在绑定更改之前检查我们视图的状态,在绑定更改之后检查我们视图的目标状态,然后应用动画从点A到点B。“ ——动画绑定

因此,将self.insetAmount设置为新的随机值后,它将立即跳至该值并将其直接传递给Trapezoid——在动画发生时它不会传递很多中间值。这就是为什么我们的梯形从插图跳到插图。它甚至不知道动画正在发生。

我们只能用四行代码来解决这个问题,其中只有一行是大括号。但是,即使这段代码很简单,它的工作方式也可能使您的大脑弯曲。

首先,现在将此新的计算属性添加到梯形结构体中:

var animatableData: CGFloat {
    get { insetAmount }
    set { self.insetAmount = newValue }
}

现在,您可以再次运行该应用程序,并通过平滑的动画查看梯形形状的变化。

这里发生的事情非常复杂:当我们使用withAnimation()时,SwiftUI会立即将状态属性更改为其新值,但在幕后,随着动画的进行,它还在跟踪随时间的值变化。随着动画的进行,SwiftUI会将 Shape 的animatableData属性设置为最新值,这取决于我们来决定这意味着什么——在本例中,我们将其直接分配给insetAmount,因为这就是我们要进行动画处理的东西。

记住,SwiftUI在应用动画之前先评估视图状态,然后再应用动画。可以看到我们最初有评估为Trapezoid(insetAmount:50)的代码,但是在选择了一个随机数之后,我们最终得到了(例如)Trapezoid(insetAmount:62)。因此,它将在动画的整个长度内插值50到62,每次将形状的animatableData属性设置为最新的插值:51、52、53,依此类推,直到达到62。

译自 Animating simple shapes with animatableData

SwiftUI:特殊效果 - 模糊,混合模式等 Hacking with iOS: SwiftUI Edition 使用 AnimatablePair 对复杂形状进行动画处理

赏我一个赞吧~~~

你可能感兴趣的:(SwiftUI:使用 animatableData 给形状设置动画)