Create custom data transitions during animations in SwiftUI
Transitionable
What It Does
SwiftUI makes it easy to animate simple interface updates, but it quickly gets complicated when you want to update custom parameters during animations.
Animatable
ViewModifier
s make it possible to smoothly change a single VectorArithmetic
conforming parameter. Chained AnimatablePair
s can handle more, but it’s messy.
Transitionable
allows you to create any changes you want to a set of parameters as an animation proceeds from 0-1.
How To Use It
Create a Transitionable
conforming struct
containing the parameters you want to transition:
struct FontDescriptor: Transitionable
{
let style: BlockFontStyle
let size: CGFloat
let weight: CGFloat
let lineSpacing: CGFloat
}
Implement transition(to:, progress:)
, defining how your parameters should change over the course of an animation – progress
will go from 0
to 1
:
func transition(_ other: FontDescriptor, progress: CGFloat) -> FontDescriptor {
let progress = progress * progress
return FontDescriptor(
style: progress < 0.5 ? style : other.style,
size: progress.lerp(min: size, max: other.size),
weight: progress.lerp(min: weight, max: other.weight),
lineSpacing: progress.lerp(min: lineSpacing, max: other.lineSpacing))
}
Add an EnvironmentKey
for your parameters:
private struct FontDescriptorKey: EnvironmentKey {
static let defaultValue = Style.fontDescriptor(for: defaultState)
}
extension EnvironmentValues {
var fontDescriptor: FontDescriptor {
get { self[FontDescriptorKey.self] }
set { self[FontDescriptorKey.self] = newValue }
}
}
Pass your parameters to child views using the View
extension:
MyTextView()
.environmentTransition(\.fontDescriptor, Style.fontDescriptor(for: someState))
Use the parameters as you wish in your View
:
struct MyTextView: View
{
@Environment(\.fontDescriptor) var fontDescriptor: FontDescriptor
var body: some View {
...
}
}