LoginSignup
24
22

More than 5 years have passed since last update.

SwiftTaskでアニメーションをすっきり実装する

Last updated at Posted at 2016-03-17

PromiseKitでアニメーションをすっきり書いている人がいて、SwiftTaskの方が好きなのですっきりかけるようにしてみた。

完成形

SwiftTaskAnimation
    let displayAnimation = UIView.animationTask(0.5, delay: 0.2, animations: {
      self.displayImageView.alpha = 1.0
    })
    let messageAnimation = UIView.animationTask(0.3, delay: 0.2, animations: {
      self.messageImageView.alpha = 1.0
    })
    let viewAnimation = UIView.animationTask(0.5, delay: 0.0, animations: {
      self.view.alpha = 1.0
    })

    //Animation Task
    viewAnimation >>> displayAnimation >>> messageAnimation

こんな感じ

まずはアニメーションをタスクで実行出来るようにする。

typealias AnimationTask = Task<NSProgress, Bool, NSError?>
extension UIView {

  class func animationTask( duration: NSTimeInterval,
                            delay: NSTimeInterval? = nil,
                            usingSpringWithDamping: CGFloat? = nil,
                            initialSpringVelocity: CGFloat? = nil,
                            options: UIViewAnimationOptions? = nil,
                            animations: (() -> Void)?,
                            completion: ((Bool) -> Void)? = nil) -> AnimationTask {

    return AnimationTask(paused: true) { progress, fulfill, reject, configure in
      if let usingSpringWithDamping = usingSpringWithDamping, initialSpringVelocity = initialSpringVelocity {
        UIView.animateWithDuration(duration, delay: delay ?? 0.0, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options ?? [], animations: { () -> Void in
          animations?()
          }, completion: { finish in
            completion?(finish)
            if finish {
              fulfill(finish)
            } else {
              reject(nil)
            }
        })
      } else {
        UIView.animateWithDuration(duration, delay: delay ?? 0.0, options: options ?? [], animations: { () -> Void in
          animations?()
          }, completion: { finish in
            completion?(finish)
            if finish {
              fulfill(finish)
            } else {
              reject(nil)
            }
        })
      }
    }

  }
}


ごちゃごちゃしているけど、バネと普通のアニメーションメソッドを一つにまとめている部分が大半で、設定されたパラメータによって使い分けている。
ちゃんとポーズさせておかないとインスタンスを作った時点でタスクが実行されたのでポーズさせる。(paused: true)のところ

infix operator >>> { associativity left }
func >>> <T: AnimationTask>(left: T, right: T) -> AnimationTask {
  let task = left.resumeSelf().then { _ -> AnimationTask in
    return right.resumeSelf()
  }
  return task
}

extension Task {
  func resumeSelf() -> Task {
    resume()
    return self
  }
}

オペーレータとresumeして自身を返すメソッドを拡張。
これでa >>> bでPromiseKitみたいにアニメーションが順々に実行されていく

あとは最初のように呼び出せばOK。オペレータが気持ち悪いのであればresumeSelf().thenでつなげていけばOK(resumeSelf()も嫌ならresumeしてからry

//追記

SwiftTaskが即時実行されてしまう問題は
@taka0125 大先輩が調べてくださいました!ありがとうございます!

24
22
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
24
22