For an Apple Vision pro project I’m working on in SwiftUI / RealityKit, I was in need of more easing functions than the build in ones that AnimationTimingFunction come with (.linear, .easeIn, .easeOut, .easeInOut). While I love that you can do your own cubic beziers, I don’t love the thought of hard coding them into my application.
So I did as anyone would do and started looking for a way to get more easing functions. Essentially I would love to be able to call any of the functions available at easings.net. Those are somewhat standard in animation by now and easy to grasp.
How to implement the code
The nice thing about SwiftUI is, that it’s really easy to extend features. You simply create a swift file anywhere in your project, add your extension code and it magically connects to whatever you want it to extend. For me it’s really felt like magic the past weeks as I’ve gotten used to how easy this is to do.
Anyway, here is the code. Drop it into a swift file named AnimationTimingFunction
. Then you can start using it. For example when you animate entities:
entity.move(to: targetTransform, relativeTo: entity.parent, duration: duration, timingFunction: .easeOutCubic)
import RealityKit
extension AnimationTimingFunction {
static var easeInSin: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.47, 0.0), controlPoint2: SIMD2<Float>(0.745, 0.715))
}
static var easeOutSin: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.39, 0.575), controlPoint2: SIMD2<Float>(0.565, 1.0))
}
static var easeInOutSine: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.445, 0.05), controlPoint2: SIMD2<Float>(0.55, 0.95))
}
static var easeInQuad: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.55, 0.085), controlPoint2: SIMD2<Float>(0.68, 0.53))
}
static var easeOutQuad: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.25, 0.46), controlPoint2: SIMD2<Float>(0.45, 0.94))
}
static var easeInOutQuad: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.455, 0.03), controlPoint2: SIMD2<Float>(0.515, 0.955))
}
static var easeInCubic: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.55, 0.055), controlPoint2: SIMD2<Float>(0.675, 0.19))
}
static var easeOutCubic: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.215, 0.61), controlPoint2: SIMD2<Float>(0.355, 1.0))
}
static var easeInQuart: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.895, 0.03), controlPoint2: SIMD2<Float>(0.685, 0.22))
}
static var easeOutQuart: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.165, 0.84), controlPoint2: SIMD2<Float>(0.44, 1.0))
}
static var easeInOutQuart: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.77, 0.0), controlPoint2: SIMD2<Float>(0.175, 1.0))
}
static var easeInQuint: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.755, 0.05), controlPoint2: SIMD2<Float>(0.855, 0.06))
}
static var easeOutQuint: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.23, 1.0), controlPoint2: SIMD2<Float>(0.32, 1.0))
}
static var easeInOutQuint: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.86, 0.0), controlPoint2: SIMD2<Float>(0.07, 1.0))
}
static var easeInExpo: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.95, 0.05), controlPoint2: SIMD2<Float>(0.795, 0.035))
}
static var easeOutExpo: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.19, 1.0), controlPoint2: SIMD2<Float>(0.22, 1.0))
}
static var easeInOutExpo: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(1.0, 0.0), controlPoint2: SIMD2<Float>(0.0, 1.0))
}
static var easeInCirc: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.6, 0.04), controlPoint2: SIMD2<Float>(0.98, 0.335))
}
static var easeOutCirc: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.075, 0.82), controlPoint2: SIMD2<Float>(0.165, 1.0))
}
static var easeInOutCirc: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.785, 0.135), controlPoint2: SIMD2<Float>(0.15, 0.86))
}
static var easeInBack: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.6, -0.28), controlPoint2: SIMD2<Float>(0.735, 0.045))
}
static var easeOutBack: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.175, 0.885), controlPoint2: SIMD2<Float>(0.32, 1.275))
}
static var easeInOutBack: AnimationTimingFunction {
return .cubicBezier(controlPoint1: SIMD2<Float>(0.68, -0.55), controlPoint2: SIMD2<Float>(0.265, 1.55))
}
}
Thoughts on learning to write in Swift
I don’t know why, but writing SwiftUI code brings me a lot of joy. It’s by no means a perfect language, but it’s weirdly fun and straight forward… even though the syntax still looks scary when I look across my code. Maybe it has more to do with XCode and the way it compiles it and how you can easily preview subviews and 3D models in isolation in the canvas? Whatever it is, it gives me good energy.
Anyway, going forward I hope to share more chunks of useful code snippets like this. (Handling transitions, string trimming, handling gestures, working with attachments… stuff like that), so feel free to subscribe to my RSS feed.