⛓ Chain multiple UIView animations without endless closure nesting. Create your animation sequence all on the same indentation level using a clear, concise syntax.
🤹 Used for all exuberant animations in OK Video 📲
📖 Check out the documentation to get up to speed, or read on to see a little example.
📦 Add AnimationPlanner to your project (using Swift Package manager) and start typing AnimationPlanner.plan to embark on your animation journey. Like what‘s happening in the code below.
AnimationPlanner.plan {
Animate(duration: 0.32, timingFunction: .quintOut) {
view.alpha = 1
view.center.y = self.view.bounds.midY
}
Wait(0.2)
Animate(duration: 0.32) {
view.transform = CGAffineTransform(scaleX: 2, y: 2)
view.layer.cornerRadius = 40
view.backgroundColor = .systemRed
}.timingFunction(.quintOut)
Wait(0.2)
AnimateSpring(duration: 0.25, dampingRatio: 0.52) {
view.backgroundColor = .systemBlue
view.layer.cornerRadius = 0
view.transform = .identity
}
Wait(0.58)
Animate(duration: 0.2) {
view.alpha = 0
view.transform = .identity
view.frame.origin.y = self.view.bounds.maxY
}.timingFunction(.circIn)
}.onComplete { finished in
view.removeFromSuperview()
}The above code results in the following animation sequence. For more examples see the Sample App available when cloning the repo.
Note: The example uses custom extension methods on CAMediaTimingFunction, included with the framework
- Go to
File->Add Packages - Paste
https://github.com/PimCoumans/AnimationPlannerin the search bar and click on "Add Package" - Select the target(s) in which you want to use AnimationPlanner
Manually add AnimationPlanner as a package dependency in package.swift, by updating your package definition with:
dependencies: [
.package(name: "AnimationPlanner", url: "https://github.com/PimCoumans/AnimationPlanner.git", .branch("main"))
],And updating your target‘s dependencies property with dependencies: ["AnimationPlanner"]
While this API removes a lot of unwanted nesting in completion closures when using traditional UIView.animate... calls, a project is never finished and for future versions I have the following plans:
- Remove usage of inaccurate
DispatchQueue.main.asyncAfter, currently used to add delays for non-UIViewanimations or bridging gaps between steps. - Maybe even allow this package to play more nicely with SwiftUI? No idea what that would look like though, any ideas?
Got any feedback or suggestions? Please let me know! ✌🏻

