UIViewPropertyAnimatorはどのようにCASpringAnimationを生成するか

Updated
Jan 21, 2021 8:31 AM
Created
Jan 21, 2021 8:23 AM
Tags
CocoaUIKit
Keywords
Date

UIView.animationやUIViewPropertyAnimatorのようなUIViewベースでのアニメーションAPIはUIKitがアニメーションを行うわけではなく、結局のところ全てCoreAnimation.frameworkのパワーによって実現されています。

なので全てのアニメーションはCAAnimationのセットで実現可能というわけです。PrivateAPIなどの都合は仕方ないですが。

UIViewPropertyAnimatorで表現できるSpringAnimationはinitialVelocityをx,yの2次元で表現可能です。 がしかし、CASpringAnimationが持つvelocityはFloatの1次元です。 直接CASpringAnimationでx,yを表現したい場合はどうしたらいいでしょうか。 UIViewPropertyAnimatorの挙動から調査します。

以下のコードをPlaygroundで実行します

import UIKit

let view = UIView()

let animator = UIViewPropertyAnimator(
  duration: 0.3,
  timingParameters: UISpringTimingParameters(
    dampingRatio: 0.6,
    initialVelocity: CGVector(dx: 1, dy: 3)
  )
)

animator.addAnimations {
  view.frame.origin.y += 10
}

animator.startAnimation()

let anims = view.layer.animationKeys()!.compactMap {
  view.layer.animation(forKey: $0)
}

anims.forEach {
  print("")
  debugPrint($0)
}

出力はこの通り

<CASpringAnimation:0x600001ed0da0; removedOnCompletion = 0; toValue = NSPoint: {0, 0}; additive = 1; fromValue = NSPoint: {0, 0}; timingFunction = linear; delegate = <UIViewAnimationState: 0x133904880>; velocity = 1; fillMode = both; duration = 0.3; damping = 43.8224; stiffness = 1333.61; mass = 1; keyPath = position>

<CABasicAnimation:0x600001ec4cc0; removedOnCompletion = 0; delegate = <UIViewAnimationState: 0x133904880>; fillMode = both; timingFunction = easeInEaseOut; duration = 0.3; toValue = 100; fromValue = 0.0; keyPath = uiFractionalProgress>

<CASpringAnimation:0x600001ec4d00; toValue = NSPoint: {0, 0}; additive = 1; fromValue = NSPoint: {0, -10}; timingFunction = linear; delegate = <UIViewAnimationState: 0x133904880>; velocity = 3; removedOnCompletion = 0; fillMode = both; duration = 0.3; damping = 43.8224; stiffness = 1333.61; mass = 1; keyPath = position>

frameの操作を複数のCASpringAnimationによって実現されている