动画是通过改变视图的状态来给视图添加平滑视图变化的能力。SwiftUI中有两种类型的动画:隐式动画
和显式动画
。
不管是哪种动画,我们都需要一个被@State
包装的状态属性值,通过这个值的改变来促使与之相关的UI刷新,继而执行动画。
隐式动画.animation(_:value:)
这是一个SwiftUI视图的修饰器。第一个参数的值是动画行为,它包linear
,easeOut
,easeIn
和easeInOut
等。第二个参数接受一个不断变化的值,即下面用到的isAnimated
,.animation
会对这个值做出反应。
@State var isAnimated: Bool = false
var body: some View {VStack {RoundedRectangle(cornerRadius: isAnimated ? 50 : 25).fill(isAnimated ? Color.red : Color.green).frame(width: isAnimated ? 100 : 300,height: isAnimated ? 100 : 300).rotationEffect(Angle(degrees: isAnimated ? 360 : 0)).offset(y: isAnimated ? -200 : 0).animation(Animation.linear(duration: 1).repeatForever(autoreverses: false),value: isAnimated).onTapGesture {isAnimated.toggle()}}}
上面代码中对RoundedRectangle
设置了动画,我们通过onTapGesture
手势触发动画,当点击后isAnimated
的值改变,RoundedRectangle
中与isAnimated
有关的UI进行刷新,因为RoundedRectangle
被.animation
动画修饰器修饰了,并且该修饰器关注isAnimated
的变化,因此与isAnimated
有关的UI将会以指定动画的方式刷新,效果如下面两个图。
动画1
动画2
duration
为了更精确地控制我们的动画,我们可以添加单次动画的持续时间。
// 动画执行时间为2秒
.animation(.easeInOut(duration: 2), value: value)
.repeatCount/.repeatForever
我们可以通过设置repeatCount(count)
或者 repeatForever()
来设置动画重复次数等等。
// 动画执行两次
.animation(.easeInOut(duration: 1).repeatCount(2), value: value)
// 动画一直重复执行
.animation(.easeInOut(duration: 1).repeatForever(), value: value)
在设置动画重复执行是可以额外设置一个参数autoreverses
,指示动画序列在向前播放后是否反向播放。
比如一个旋转动画,从0度到360度,一直循环执行:
- 如果
autoreverses
为false
,当动画执行旋转到360度后,瞬间重置到0度,然后再从0度到360度做动画,这样反复执行,效果如上面动画1. - 如果
autoreverses
为true
,当动画执行旋转到360度后,再从360度做动画回到0度,然后再从0度动画到360,这样反复执行,效果如上面动画2.
显示动画withAnimation()
显式动画不是视图修饰器。而是调用withAnimation()
函数,并在括号之间添加想要动画化的内容。
在下面的代码中,我们在onTapGesture
的执行代码快中调用withAnimation()
函数,并设置动画参数,在withAnimation
的闭包体里改变isAnimated
的状态值,继而促使UI刷新,执行动画。
@State var isAnimated: Bool = false
var body: some View {VStack {RoundedRectangle(cornerRadius: isAnimated ? 50 : 25).fill(isAnimated ? Color.red : Color.green).frame(width: isAnimated ? 100 : 300,height: isAnimated ? 100 : 300).rotationEffect(Angle(degrees: isAnimated ? 360 : 0)).offset(y: isAnimated ? -200 : 0).onTapGesture {withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: true)) {isAnimated.toggle()}}}}
我们将isAnimated
的改变放到了withAnimation
函数的闭包里,意味着因isAnimated
的改变引起的UI变化都要以指定的动画方式执行。该段代码的执行效果如同上面的两个动画图。
内置动画类型
在SwiftUI中,系统提供了多种内置的动画类型,可以通过.animation()
修饰器或者withAnimation()
来应用这些动画效果。以下是一些常见的系统动画类型:
linear
:线性动画,以恒定速度进行动画过渡。easeIn
:缓慢开始的动画,逐渐加速。easeOut
:缓慢结束的动画,逐渐减速。easeInOut
:缓慢开始和结束的动画,先加速后减速。easeInOut(duration: Double)
:缓慢开始和结束的动画,可以指定持续时间。spring
:弹簧动画,具有弹性效果。interactiveSpring(response: Double, dampingFraction: Double, blendDuration: Double)
:交互式弹簧动画,可以调整响应、阻尼和混合持续时间。default
:默认动画,系统根据情况选择合适的动画类型。