Updated for Xcode 14.2
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 In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.