152
144

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

iOS10からのAnimationがいい感じ!

Last updated at Posted at 2016-06-24

こんにちは。現在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

}
  • メソッド名はシンプルになって、第一引数も外部名が表記するようになっています。
  • UIViewAnimationOptionslowerCamelCaseになっている
  • 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周りのクラス図

Screen Shot 2016-06-22 at 11.32.31.png

  • UIViewAnimatingとUIViewImplicitlyというプロトコルに準拠しています。
  • UITimingCurveProviderというプロトコルに準拠したオブジェクトを受け取って、アニメーションのタイミングを調整します。

UIViewAnimatingプロトコル

アニメーションのフローを制御するメソッドやプロパティが定義されている。

メソッド

  • func startAnimation()
  • func pauseAnimation()
    • アニメーションの一時停止
    • AnimatingStateactiveのまま
  • 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次ベジェ曲線を定義する

cubic.png

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は初期の方向と速度

間違っていたら教えてください。正直、うまい値の渡し方がわかりません笑

Jun-22-2016 17-08-52.gif

このクラスをうまく使うと、このようなアニメーションが実現できるようです!
すごい!!!

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年後くらいまで使えない!
  • セッション動画はこちらです!!
152
144
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
152
144

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?