![2f1e18350f50ab55b986ff460e4876ca.png](https://img-blog.csdnimg.cn/img_convert/2f1e18350f50ab55b986ff460e4876ca.png)
相信大家都已经对SwiftUI有了基本的了解,在SwiftUI写动画,相对来说变得更加简单了,接下来,会用3篇文章,带领大家一览SwiftUI动画的魅力。
1. 显式和隐式动画
在SwiftUI中有两种类型的动画,显式和隐式。
隐式动画指的就是用animation()
modifier的view,当该view的可动画的参数变化的时候,系统会自动进行动画,这些所谓的可动画的参数包括size
,offset
,color
,scale
等等。
显式动画指的是withAnimation { ... }
闭包中指定的参数,所有依赖这些参数的view,都会执行动画。
我们先看个例子,下边的动画使用了隐式动画:
![edfc1a82f3aefb20954416585b26df07.gif](https://img-blog.csdnimg.cn/img_convert/edfc1a82f3aefb20954416585b26df07.gif)
代码如下:
struct Example1: View {
@State private var half = false
@State private var dim = false
var body: some View {
Image("tower")
.scaleEffect(half ? 0.5 : 1.0)
.opacity(dim ? 0.2 : 1.0)
.animation(.easeInOut(duration: 1.0))
.onTapGesture {
self.dim.toggle()
self.half.toggle()
}
}
}
从上边的代码中,我们可以看出动画依赖half
,dim
这2个参数,我们并没有直接告诉view这2个参数要动画,系统会自动把旧值到新值的变化做动画。
我们把代码做一点简单的改变:
struct Example2: View {
@State private var half = false
@State private var dim = false
var body: some View {
Image("tower")
.scaleEffect(half ? 0.5 : 1.0)
.opacity(dim ? 0.5 : 1.0)
.onTapGesture {
self.half.toggle()
withAnimation(.easeInOut(duration: 1.0)) {
self.dim.toggle()
}
}
}
}
我们去掉了.animation(.easeInOut(duration: 1.0))
,新增了withAnimation
闭包,我们把self.dim.toggle()
放到闭包中,这就是显式的告诉系统,view的透明度要执行xxx动画,所有依赖dim
参数的view,在dim改变的时候,都会执行动画,效果如下:
![f954984ffcca2c96c4a63aa8061297bd.gif](https://img-blog.csdnimg.cn/img_convert/f954984ffcca2c96c4a63aa8061297bd.gif)
仔细看上图的动画过程,就会发现,只有透明度指定了动画,缩放并没有执行动画,这就说明,我们显式的告诉系统dim
需要动画,它就只为dim
执行动画,非常的听话。
此时此刻,我有一个问题,我用隐式动画如何实现上边这种动画呢?也非常简单,先看代码:
struct Example2: View {
@State private var half = false
@State private var dim = false
var body: some View {
Image("tower")
.opacity(dim ? 0.2 : 1.0)
.animation(.easeInOut(duration: 1.0))
.scaleEffect(half ? 0.5 : 1.0)
.onTapGesture {
self.dim.toggle()
self.half.toggle()
}
}
}
当animation
modifier作用于view时,他的顺序时很重要的,在上边的代码中,它只对它前边的内容生效,当然这个顺序我们其实时可以任意调整的,我们要想使用隐式动画禁用某些动画时,只需要.animation(nil)
就行了。
struct Example2: View {
@State private var half = false
@State private var dim = false
var body: some View {
Image("tower")
.opacity(dim ? 0.2 : 1.0)
.animation(nil)
.scaleEffect(half ? 0.5 : 1.0)
.animation(.easeInOut(duration: 1.0))
.onTapGesture {
self.dim.toggle()
self.half.toggle()
}
}
}
2.How Do Animations Work
SwiftUI动画背后的原理在于Animatable
协议,它要求我们实现一个计算属性animatableData
,该属性遵守VectorArithmetic
协议,VectorArithmetic
的目的是让系统可以在需要变化的动画数据中间插入很多值,这些值的计算依赖动画的时间函数。
本质上,在SwiftUI中执行动画,就是系统渲染View很多次,每一次渲染,都改变一点点参数,当然,这个参数指的是需要动画的原值到终值。
举个例子,如果我们线性的把透明度从0.3改成0.8,由于0.3是Double
类型,实现了VectorArithmetic
协议,因此系统可以在0.3到0.8之间插入很对中间的值,这些值的计算依赖时间函数和动画时长。在本例中,它是线性的,系统在插