今回は Swift
の UIView.animate
で連続したアニメーションを実行する際のコールバック地獄を解消する方法を紹介したいと思います👀
結論
今回の悩みを解消できる素晴らしい記事があったので、車輪の再発明はしません✨
Swift の Variadic Parameters
を使って、複数のアニメーションブロックを再帰関数で実行していく感じです。ここで定義した Extension method
を使うことで、あのコールバック地獄から抜け出せます🦅
extension UIView { public static func animate(eachBlockDuration duration: TimeInterval, eachBlockDelay delay: TimeInterval = 0, eachBlockOptions options: UIView.AnimationOptions = .curveEaseInOut, animationBlocks: (() -> Void)..., completion: ((_ finished: Bool) -> Void)? = nil) { let isFinished = animationBlocks.isEmpty if isFinished { completion?(isFinished) } else { let animationArraySlice = ArraySlice(animationBlocks) UIView.animate(eachBlockDuration: duration, eachBlockDelay: delay, eachBlockOptions: options, animationArraySlice: animationArraySlice, completion: completion) } } private static func animate(eachBlockDuration duration: TimeInterval, eachBlockDelay delay: TimeInterval, eachBlockOptions options: UIView.AnimationOptions, animationArraySlice: ArraySlice<() -> Void>, completion: ((_ finished: Bool) -> Void)?) { let animation = animationArraySlice.startItem UIView.animate(withDuration: duration, delay: delay, options: options, animations: animation) { (finished) in let remainedAnimations = animationArraySlice.dropFirst() if remainedAnimations.isEmpty { completion?(finished) } else { UIView.animate(eachBlockDuration: duration, eachBlockDelay: delay, eachBlockOptions: options, animationArraySlice: remainedAnimations, completion: completion) } } } }
使う時はこんな感じ
UIView.animate(eachBlockDuration: 0.3, eachBlockDelay: 0.3, eachBlockOptions: .curveEaseOut, animationBlocks: {[weak self] in self?.view.alpha = 1.0 }, {[weak self] in self?.view.alpha = 0.0 }, completion: {[weak self] finished in // TODO: Completion handle. }) }