Last active
November 30, 2023 01:09
-
-
Save heestand-xyz/b85f9f6f85b8d85a7bbe4f79a51eae7f to your computer and use it in GitHub Desktop.
Animator with Easing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import CoreGraphics | |
#if os(iOS) | |
import UIKit | |
#endif | |
struct Animator { | |
enum AnimationEase { | |
case linear | |
case easeIn | |
case easeInOut | |
case easeOut | |
} | |
@discardableResult | |
static func animate(for duration: CGFloat, | |
ease: AnimationEase = .linear, | |
loop: @escaping (CGFloat) -> (), | |
done: (() -> ())? = nil) -> Timer { | |
let startTime: Date = .now | |
#if os(macOS) | |
let refreshRate: Double = { | |
let id = CGMainDisplayID() | |
guard let display = CGDisplayCopyDisplayMode(id) else { return 60 } | |
return display.refreshRate | |
}() | |
#elseif os(visionOS) | |
let refreshRate = 90.0 | |
#else | |
let refreshRate = Double(UIScreen.main.maximumFramesPerSecond) | |
#endif | |
loop(0.0) | |
return .scheduledTimer(withTimeInterval: 1.0 / refreshRate, repeats: true) { timer in | |
let elapsedTime = CGFloat(-startTime.timeIntervalSinceNow) | |
let fraction = min(elapsedTime / duration, 1.0) | |
let easeFraction = switch ease { | |
case .linear: | |
fraction | |
case .easeIn: | |
cos(fraction * .pi / 2 - .pi) + 1 | |
case .easeInOut: | |
cos(fraction * .pi - .pi) / 2 + 0.5 | |
case .easeOut: | |
cos(fraction * .pi / 2 - .pi / 2) | |
} | |
loop(easeFraction) | |
if fraction == 1.0 { | |
done?() | |
timer.invalidate() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment