Updated for Xcode 12.0
SwiftUI doesn’t have a built-in way to animate text size, but we can create an AnimatableModifier
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.
First, we need an AnimatableModifier
that accepts a name and size, and uses the size property for its animatable data:
struct AnimatableCustomFontModifier: AnimatableModifier {
var name: String
var size: CGFloat
var animatableData: CGFloat {
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: CGFloat) -> some View {
self.modifier(AnimatableCustomFontModifier(name: name, size: size))
}
}
That’s it! To try it out, make an @State
property to store your font size, then pass that into animatableFont()
.
For example, this will scale the text “Hello, World!” up and down, using Georgia:
struct ContentView: View {
@State private var fontSize: CGFloat = 32
var body: some View {
Text("Hello, World!")
.animatableFont(name: "Georgia", size: fontSize)
.onTapGesture {
withAnimation(Animation.spring(response: 0.5, dampingFraction: 0.5, blendDuration: 1).repeatForever()) {
self.fontSize = 144
}
}
}
}
If you wanted to use Apple’s system fonts, the best way to do that is with a separate AnimatableModifier
:
struct AnimatableSystemFontModifier: AnimatableModifier {
var size: CGFloat
var weight: Font.Weight
var design: Font.Design
var animatableData: CGFloat {
get { size }
set { size = newValue }
}
func body(content: Content) -> some View {
content
.font(.system(size: size, weight: weight, design: design))
}
}
That also works better when wrapped in a View
extension such as this:
extension View {
func animatableSystemFont(size: CGFloat, weight: Font.Weight = .regular, design: Font.Design = .default) -> some View {
self.modifier(AnimatableSystemFontModifier(size: size, weight: weight, design: design))
}
}
I first saw this technique applied in Apple sample code, and by using the system font you’re making sure your UI stays updated if the font ever changes.
SPONSORED Would you describe yourself as knowledgeable, but struggling when you have to come up with your own code? Fernando Olivares has a new book containing iOS rules you can immediately apply to your coding habits to see dramatic improvements, while also teaching applied programming fundamentals seen in refactored code from published apps.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.