SwiftUI 动画 –- Animatable

109 阅读2分钟

所有 SwiftUI 动画的背后都有一个名为<strong>Animatable</strong>,主要涉及具有符合**VectorArithmetic**.

当对视图进行动画处理时,SwiftUI 实际上会多次重新生成视图,并且每次都会修改动画参数。这样它就会从原始值逐渐变为最终值。

显式与隐式动画

隐式动画

使用.animation()修饰符指定的动画。每当视图上的可动画参数发生更改时,SwiftUI 就会从旧值动画到新值。一些可设置动画的参数包括大小、偏移、颜色、比例等。

显式动画

用闭包withAnimation { ... }指定的动画。只有那些依赖于 withAnimation 闭包内更改的值的参数才会被动画化。让我们尝试一些例子来说明:

AnimatablePair

浏览 SwiftUI 声明文件,您会发现该框架使用AnimatablePair相当广泛。例如:CGSizeCGPointCGRect。尽管这些类型不符合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

  • AngleCGPointCGRectCGSizeEdgeInsetsStrokeStyle UnitPoint

使您自己的类型可动画化(使用 VectorArithmetic)

以下类型符合VectorArithmeticAnimatablePairCGFloatDoubleEmptyAnimatableDataFloat。您可以使用它们中的任何一个来为您的形状设置动画。

现有类型提供了足够的灵活性来为任何内容设置动画。但是,如果您发现自己想要为复杂类型设置动画,您可以为自己类的添加 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 
  } 
}