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 大先輩が調べてくださいました!ありがとうございます!