Updated for Xcode 13.3
SwiftUI doesn’t have a built-in way to animate text size, but we can create an animatable view modifier that makes the effect possible. This is not the same as using a simple scaleEffect()
modifier – that will cause your text to become blurry when scaled up, whereas this custom animation will re-render your text correctly so it looks great at all sizes.
This takes several steps:
View
extension to make it easier to use.View
.Here’s a complete example in code:
// A modifier that animates a font through various sizes.
struct AnimatableCustomFontModifier: ViewModifier, Animatable {
var name: String
var size: Double
var animatableData: Double {
get { size }
set { size = newValue }
}
func body(content: Content) -> some View {
content
.font(.custom(name, size: size))
}
}
// To make that easier to use, I recommend wrapping
// it in a `View` extension, like this:
extension View {
func animatableFont(name: String, size: Double) -> some View {
self.modifier(AnimatableCustomFontModifier(name: name, size: size))
}
}
// An example View trying it out
struct ContentView: View {
@State private var fontSize = 32.0
var body: some View {
Text("Hello, World!")
.animatableFont(name: "Georgia", size: fontSize)
.onTapGesture {
withAnimation(.spring(response: 0.5, dampingFraction: 0.5, blendDuration: 1).repeatForever()) {
fontSize = 72
}
}
}
}
Download this as an Xcode project
That’s it! To try it out, make an @State
property to store your font size, then pass that into animatableFont()
.
If you wanted to use Apple’s system fonts, the best way to do that is with a separate modifier. This way you can be sure your UI stays updated if the font ever changes.
Here’s how that looks:
struct AnimatableSystemFontModifier: ViewModifier, Animatable {
var size: Double
var weight: Font.Weight
var design: Font.Design
var animatableData: Double {
get { size }
set { size = newValue }
}
func body(content: Content) -> some View {
content
.font(.system(size: size, weight: weight, design: design))
}
}
extension View {
func animatableSystemFont(size: Double, weight: Font.Weight = .regular, design: Font.Design = .default) -> some View {
self.modifier(AnimatableSystemFontModifier(size: size, weight: weight, design: design))
}
}
struct ContentView: View {
@State private var fontSize = 32.0
var body: some View {
Text("Hello, World!")
.animatableSystemFont(size: fontSize)
.onTapGesture {
withAnimation(.spring(response: 0.5, dampingFraction: 0.5, blendDuration: 1).repeatForever()) {
fontSize = 72
}
}
}
}
Download this as an Xcode project
I first saw this technique applied in Apple sample code.
SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.