//: | |
//: UIView Animation Syntax Sugar | |
//: | |
//: Created by Andyy Hope on 18/08/2016. | |
//: Twitter: @andyyhope | |
//: Medium: Andyy Hope, https://medium.com/@AndyyHope | |
import UIKit | |
extension UIView { | |
class Animator { | |
typealias Completion = (Bool) -> Void | |
typealias Animations = () -> Void | |
private var animations: Animations | |
private var completion: Completion? | |
private let duration: TimeInterval | |
private let delay: TimeInterval | |
private let options: UIViewAnimationOptions | |
init(duration: TimeInterval, delay: TimeInterval = 0, options: UIViewAnimationOptions = []) { | |
class Animator { | |
typealias Completion = (Bool) -> Void | |
typealias Animations = () -> Void | |
fileprivate var animations: Animations | |
fileprivate var completion: Completion? | |
fileprivate let duration: TimeInterval | |
fileprivate let delay: TimeInterval | |
fileprivate let options: UIViewAnimationOptions | |
init(duration: TimeInterval, delay: TimeInterval = 0, options: UIViewAnimationOptions = []) { | |
self.animations = {} | |
self.completion = nil | |
self.duration = duration | |
self.delay = delay | |
self.options = options | |
} | |
func animations(_ animations: @escaping Animations) -> Self { | |
self.animations = animations | |
return self | |
} | |
func completion(_ completion: @escaping Completion) -> Self { | |
self.completion = completion | |
return self | |
} | |
func animate() { | |
UIView.animate(withDuration: duration, delay: delay, animations: animations, completion: completion) | |
} | |
} | |
final class SpringAnimator: Animator { | |
fileprivate let damping: CGFloat | |
fileprivate let velocity: CGFloat | |
init(duration: TimeInterval, delay: TimeInterval = 0, damping: CGFloat, velocity: CGFloat, options: UIViewAnimationOptions = []) { | |
self.damping = damping | |
self.velocity = velocity | |
super.init(duration: duration, delay: delay, options: options) | |
} | |
override func animate() { | |
UIView.animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: velocity, options: options, animations: animations, completion: completion) | |
} | |
} | |
} | |
// MARK: - Example API | |
var view = UIView(frame: .zero) | |
// Regular Animations | |
UIView.Animator(duration: 0.3) | |
.animations { | |
view.frame.size.height = 100 | |
view.frame.size.width = 100 | |
} | |
.completion { finished in | |
view.backgroundColor = .black | |
} | |
.animate() | |
// Regular Animations with options | |
UIView.Animator(duration: 0.4, delay: 0.2) | |
.animations { } | |
.completion { _ in } | |
.animate() | |
UIView.Animator(duration: 0.4, options: [.autoreverse, .curveEaseIn]) | |
.animations { } | |
.completion { _ in } | |
.animate() | |
UIView.Animator(duration: 0.4, delay: 0.2, options: [.autoreverse, .curveEaseIn]) | |
.animations { } | |
.completion { _ in } | |
.animate() | |
// Spring Animator | |
UIView.SpringAnimator(duration: 0.3, delay: 0.2, damping: 0.2, velocity: 0.2, options: [.autoreverse, .curveEaseIn]) | |
.animations { } | |
.completion { _ in } | |
.animate() |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
That's a much nicer interface to the existing UIView animations api, you did an awesome job. I updated some existing code after looking at what you have done and the result is: public extension UIView {
public class Animator {
public typealias Completion = (Bool) -> Void
public typealias Animations = () -> Void
public convenience init(duration: TimeInterval, delay: TimeInterval = 0, options: UIViewAnimationOptions = []) {
self.init(animationType: .regular(duration, delay, options))
}
public convenience init(duration: TimeInterval, delay: TimeInterval = 0, damping: CGFloat, velocity: CGFloat, options: UIViewAnimationOptions = []) {
self.init(animationType: .spring(duration, delay, damping, velocity, options))
}
public func animations(_ animations: @escaping Animations) -> Self {
self.animations = animations
return self
}
public func completion(_ completion: Completion?) -> Self {
self.completion = completion
return self
}
public func animate() {
switch self.animationType {
case let .regular(duration, delay, options):
UIView.animate(withDuration: duration, delay: delay, options: options, animations: self.animations, completion: self.completion)
case let .spring(duration, delay, dampingRatio, velocity, options):
UIView.animate(withDuration: duration, delay: delay, usingSpringWithDamping: dampingRatio, initialSpringVelocity: velocity, options: options, animations: self.animations, completion: self.completion)
}
}
// MARK: - Private stuff
private enum AnimationType {
case regular(TimeInterval, TimeInterval, UIViewAnimationOptions)
case spring(TimeInterval, TimeInterval, CGFloat, CGFloat, UIViewAnimationOptions)
}
private let animationType: AnimationType
private var animations: Animations = {}
private var completion: Completion? = nil
private init(animationType: AnimationType) {
self.animationType = animationType
}
}
} I like to have the |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Nice work; I like it!
I don't see, however, any way for the delay or the options to make their way through to the system API. Is there a cut/paste error in there somewhere?