こんにちは。現在Standard Cognition( https://standard.ai )というSFにある会社でSoftware Engineerをやっている原健太です(Twitterアカウント)
WWDC16で、iOS10から使えるアニメーションに関する新しい発表がありました。
動的なアニメーションの追加や、一時停止など、柔軟にいろんな事ができるようになっていたので、紹介したいと思います!
従来のアニメーション
まず、従来のアニメーションは、こんな感じで書いていたかと思います。
UIView.animateWithDuration(2.0, delay: 0, options: .CurveEaseInOut, animations: {
// animation
}) { _ in
// completion
}
まず、こちらのメソッドも、Swift3からはこんな感じに変わります!
UIView.animate(withDuration: 2.0, delay: 0, options: [.curveEaseIn, .curveEaseOut], animations: {
}) { _ in
}
- メソッド名はシンプルになって、第一引数も外部名が表記するようになっています。
-
UIViewAnimationOptions
がlowerCamelCase
になっている -
curveEaseInOut
が無かったのですが、それを実現するには、このようにするんですかね、、??
ただ、これも、動的にいろんな操作をするには向いていません。
だからといって、CoreAnimation
も分かりづらかったり、beginFromCurrentState
というoptionの挙動もわかりづらい、、、
そこで登場したのが、 UIViewPropertyAnimatorです!こちらのクラスを使うと、アニメーションに対していろんな柔軟な対応ができるようになっています!
UIViewPropertyAnimator
ざっと、このような感じで使います!
let timing = UICubicTimingParameters(animationCurve: .easeInOut)
let animator = UIViewPropertyAnimator(duration: 2.0, timingParameters: timing)
animator.addAnimations {
// animation
}
animator.startAnimation()
animator.pauseAnimation()
なんだか、いろいろできそうな予感がします。
@IBAction func handlePan(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.view)
let translatedCenterY = view.center.y + translation.y
let progress = translatedCenterY / self.view.bounds.size.height
animator.fractionComplete = progress
}
このように、ユーザのジェスチャに応じてアニメーションの進行を操作することもできます。
UIViewPropertyAnimator周りのクラス図
- UIViewAnimatingとUIViewImplicitlyというプロトコルに準拠しています。
- UITimingCurveProviderというプロトコルに準拠したオブジェクトを受け取って、アニメーションのタイミングを調整します。
UIViewAnimatingプロトコル
アニメーションのフローを制御するメソッドやプロパティが定義されている。
メソッド
func startAnimation()
-
func pauseAnimation()
- アニメーションの一時停止
-
AnimatingState
はactive
のまま
-
func stopAnimation(_ withoutFinishing: Bool)
- アニメーションを現在のポジションで終了させたい時に利用する
- 引数にtrueを渡すと直接
inactive
のステートに変化する - 引数にfalseを渡すと、
stopped
ステートに変化し、終了させるにはfinishAnimation
メソッドを呼ぶ
-
func finishAnimation(at: UIViewAnimatingPosition)
-
stopped
ステートの時にこのメソッドを呼んでアニメーションを終了させる -
stopped
ステートに遷移する前にこのメソッドを呼ぶとエラーになる。 -
inactive
ステートに遷移する
-
プロパティ
-
var fractionComplete: CGFloat
- アニメーションの完了度合いのパーセンテージ
- 0.0 - 1.0の値をとる
- この値を操作することにより、アニメーションをインテラクティブに操作できる
-
var isReversed: Bool
- このプロパティを操作することによってアニメーションの方向を操作できる
-
var state: UIViewAnimatingState
Enumで
- inactive
- active
- stopped
の3つの値を持つ
-
var isRunning: Bool
- アニメーションが進行中かどうか
UIViewImplicitlyAnimatingプロトコル
アニメーションのカスタマイズに関するメソッドが定義されている
メソッド
-
func addAnimations(() -> Void)
- アニメーションを定義する
-
func addAnimations(() -> Void, delayFactor: CGFloat)
- 元々のアニメーションに対して、途中から別のアニメーションを開始する場合などに利用する
-
delayFactor
には0.0 - 1.0の値を入れる - 例えば、0.7を入れたら、元々のアニメーションの7割が終了した時点で、追加のアニメーションが開始される
-
func addCompletion((UIViewAnimatingPosition) -> Void)
- アニメーションが終了したときの処理を記述する
UIViewAnimatingPositionはEnumで、
- end
- start
- current
の3つの値がある
-
func continueAnimation(withTimingParameters: UITimingCurveProvider?, durationFactor: CGFloat)
- pauseしているアニメーションに対して、タイミングや、durationを変更して再開したい場合に利用する
-
durationFactor
の値と、元々のduration
を掛けた値が最終的なduration
になる
UICubicTimingParameters
アニメーションのタイミングを定義するクラス
イニシャライズ
init()
init(animationCurve: UIViewAnimationCurve)
UIViewAnimationCurve
には
- case easeInOut // slow at beginning and end
- case easeIn // slow at beginning
- case easeOut // slow at end
- case linear
の4つが定義されている
-
init(controlPoint1: CGPoint, controlPoint2: CGPoint)
- 2つの点を定義することにより、3次ベジェ曲線を定義する
UISpringTimingParameters
このクラスのオブジェクトをUIViewPropertyAnimator
に渡す事によってバネのような動きのアニメーションを実現できる
イニシャライズ
init()
-
init(dampingRatio: CGFloat)
- 減衰比を渡す
- 0.0 - 1.0の値を取り、小さいほど揺れが大きくなる
-
init(dampingRatio: CGFloat, initialVelocity: CGVector)
- 上記のに加え、初期の方向と速度を渡すことができる
-
init(mass: CGFloat, stiffness: CGFloat, damping: CGFloat, initialVelocity: CGVector)
-
mass
は質量 -
stiffness
はバネの硬さ?? -
damping
は減衰の強さ?? -
initialVelocity
は初期の方向と速度
-
間違っていたら教えてください。正直、うまい値の渡し方がわかりません笑
このクラスをうまく使うと、このようなアニメーションが実現できるようです!
すごい!!!
UIViewControllerAnimatedTransitioning
UIViewPropetyAnimator
を用いたアニメーションは画面遷移にも使えるようです!!
func animateTransition(_ transitionContext: UIViewControllerContextTransitioning) {
self.interruptibleAnimator(forTransition: transitionContext)?.startAnimation(
}
func interruptibleAnimator(forTransition transitionContext: UIViewControllerContextTransitioning?) -> UIViewImplicitlyAnimating? {
let timing = UICubicTimingParameters(animationCurve: .easeInOut)
let animator = UIViewPropertyAnimator(duration: 2.0, timingParameters: timing)
animator.addAnimations {
// animation
}
return animator
}
のように、新しく追加されたinterruptibleAnimator
メソッドでUIViewPropertyAnimator
のオブジェクトを返して、従来使っていたanimateTransition
メソッドでアニメーションを開始してあげる、という流れです。
まとめ
- なんだか気持ち良いアニメーションが作りたくなった
- iOS10からの対応なので、半年後とか1年後くらいまで使えない!
- セッション動画はこちらです!!