Skip to content

Instantly share code, notes, and snippets.

@daehn
Last active June 22, 2017 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daehn/77a4256631892aa8566ee7191e345914 to your computer and use it in GitHub Desktop.
Save daehn/77a4256631892aa8566ee7191e345914 to your computer and use it in GitHub Desktop.
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
extension Comparable {
/// Clamp the value between `low` and `high`
func clamp(_ low: Self, _ high: Self) -> Self {
return min(high, max(low, self))
}
}
class InterpolatingAnimator: NSObject {
enum Interpolation {
case linear
case easeOut
case custom((CGFloat) -> CGFloat)
func transform(_ t: CGFloat) -> CGFloat {
switch self {
case .linear: return t
case .easeOut: return t * (2 - t)
case .custom(let transform): return transform(t)
}
}
}
typealias InterpolationUpdate = (CGFloat, Bool) -> Void
private var displayLink: CADisplayLink!
private let interpolation: Interpolation
private let update: InterpolationUpdate
private let duration: TimeInterval
private let from: CGFloat
private let to: CGFloat
private var timeRunning: CFTimeInterval = 0
init(_ interpolation: Interpolation, duration: TimeInterval, fromValue: CGFloat, toValue: CGFloat, execute: @escaping
InterpolationUpdate) {
self.interpolation = interpolation
self.duration = duration
from = fromValue
to = toValue
update = execute
super.init()
self.displayLink = CADisplayLink(target: self, selector: #selector(updateProgress))
}
private dynamic func updateProgress() {
timeRunning += displayLink.duration
let progress = CGFloat(timeRunning / duration).clamp(0, 1)
let value = from + abs(to - from) * interpolation.transform(progress)
let finished = progress >= 1
update(value, finished)
if finished {
displayLink.remove(from: .current, forMode: .commonModes)
}
}
public func start() {
update(from, false)
displayLink.add(to: .current, forMode: .commonModes)
}
}
let label = UILabel()
label.frame = CGRect(x: 0, y: 0, width: 100, height: 50)
label.backgroundColor = .white
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = 1
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
var animator: InterpolatingAnimator?
animator = InterpolatingAnimator(.easeOut, duration: 2, fromValue: 3, toValue: 4) { value, finished in
guard let text = formatter.string(from: NSNumber(value: Double(value))) else { return }
label.text = text
print(text)
if finished {
PlaygroundPage.current.finishExecution()
animator = nil
}
}
animator?.start()
PlaygroundPage.current.liveView = label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment