iOS10からのAnimationがいい感じ!
※コチラの記事は、Qiitaのこちらの記事と同じ内容です。
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年後くらいまで使えない!
- セッション動画はこちらです!!