所有 SwiftUI 动画的背后都有一个名为<strong>Animatable</strong>,主要涉及具有符合**VectorArithmetic**.
当对视图进行动画处理时,SwiftUI 实际上会多次重新生成视图,并且每次都会修改动画参数。这样它就会从原始值逐渐变为最终值。
显式与隐式动画
隐式动画
使用.animation()修饰符指定的动画。每当视图上的可动画参数发生更改时,SwiftUI 就会从旧值动画到新值。一些可设置动画的参数包括大小、偏移、颜色、比例等。
显式动画
用闭包withAnimation { ... }指定的动画。只有那些依赖于 withAnimation 闭包内更改的值的参数才会被动画化。让我们尝试一些例子来说明:
AnimatablePair
浏览 SwiftUI 声明文件,您会发现该框架使用AnimatablePair相当广泛。例如:CGSize,CGPoint,CGRect。尽管这些类型不符合VectorArithmetic,但它们可以进行动画处理,因为它们确实符合Animatable。
extension CGPoint : Animatable {
public typealias AnimatableData = AnimatablePair<CGFloat, CGFloat>
public var animatableData: CGPoint.AnimatableData
}
extension CGSize : Animatable {
public typealias AnimatableData = AnimatablePair<CGFloat, CGFloat>
public var animatableData: CGSize.AnimatableData
}
extension CGRect : Animatable {
public typealias AnimatableData = AnimatablePair<CGPoint.AnimatableData, CGSize.AnimatableData>
public var animatableData: CGRect.AnimatableData
}
以下类型符合Animatable:
Angle、CGPoint、CGRect、CGSize、EdgeInsets和StrokeStyleUnitPoint
使您自己的类型可动画化(使用 VectorArithmetic)
以下类型符合VectorArithmetic:AnimatablePair、CGFloat、Double和EmptyAnimatableData,Float。您可以使用它们中的任何一个来为您的形状设置动画。
现有类型提供了足够的灵活性来为任何内容设置动画。但是,如果您发现自己想要为复杂类型设置动画,您可以为自己类的添加 VectorArithmetic来实现。如下面的例子:
extension ClockTime: VectorArithmetic {
static var zero: ClockTime {
return ClockTime(0, 0, 0)
}
var magnitudeSquared: Double {
return asSeconds * asSeconds
}
static func -= (lhs: inout ClockTime, rhs: ClockTime) {
lhs = lhs - rhs
}
static func - (lhs: ClockTime, rhs: ClockTime) -> ClockTime {
return ClockTime(lhs.asSeconds - rhs.asSeconds)
}
static func += (lhs: inout ClockTime, rhs: ClockTime) {
lhs = lhs + rhs
}
static func + (lhs: ClockTime, rhs: ClockTime) -> ClockTime {
return ClockTime(lhs.asSeconds + rhs.asSeconds)
}
mutating func scale(by rhs: Double) {
var s = Double(self.asSeconds) s.scale(by: rhs)
let ct = ClockTime(s)
self.hours = ct.hours self.minutes = ct.minutes self.seconds = ct.seconds
}
}