Animate Text size change in SwiftUI
One way to animation the change in text size is to use scale effect, however the text will appear blurred when scaled up. A custom AnimatableModifier can be used to smoothly animate the resizing of text in SwiftUI, which results in displaying clear text at all sizes through the animation.
Text size change without animation
Create a Text View and change the font size and font weight with an easeInOut
animation. The font size and weight changes immediately and animates into the correct
position.
1struct ContentView: View {
2 @State var small = true
3
4 var body: some View {
5 VStack {
6 Text("Plain Text")
7 .font(.system(size: 24))
8 .frame(width: 350, height: 50, alignment: .leading)
9
10 Text("Text - not animated")
11 .font(.system(size: small ? 24 : 36))
12 .fontWeight(small ? .none : .bold)
13 .frame(width: 350, height: 50, alignment: .leading)
14 .onTapGesture {
15 withAnimation(.easeInOut(duration: 1)){
16 small.toggle()
17 }
18 }
19
20 Spacer()
21 }
22 }
23}
Text with default animation - size jumps to final size
Scale Text size with animation
Use scaleEffect to change the text size with animation. Now the text grows and shrinks with the animated effect, however the text is blurred as the text grows. This is more noticeable at larger sizes.
1 Text("Text - Scaled")
2 .font(.system(size: 24))
3 .fontWeight(small ? .regular : .bold)
4 .frame(width: 350, height: 50, alignment: .leading)
5 .scaleEffect(small ? 1.0 : 1.5, anchor: .leading)
6 .onTapGesture {
7 withAnimation(.easeInOut(duration: 1)){
8 small.toggle()
9 }
10 }
Text scaled with animation - large text is blurred
Change Text size with custom AnimatableModifier
A custom AnimatableModifier as described in How to animate a Shape change in SwiftUI and Flip a card in SwiftUI is defined to animate the font size change. The size is used as the animatableData so SwiftUI knows how to render font at all the intermediate sizes resulting in a smooth animation.
1struct AnimatableFontModifier: AnimatableModifier {
2 var size: Double
3 var weight: Font.Weight = .regular
4 var design: Font.Design = .default
5
6 var animatableData: Double {
7 get { size }
8 set { size = newValue }
9 }
10
11 func body(content: Content) -> some View {
12 content
13 .font(.system(size: size, weight: weight, design: design))
14 }
15}
The AnimatableFontModifier
is used to modify the Text View to animate the size
change.
1 Text("Size Animated")
2 .modifier(AnimatableFontModifier(size: small ? 24 : 36,
3 weight: small ? .regular : .bold))
4 .frame(width: 350, height: 50, alignment: .leading)
5 .onTapGesture {
6 withAnimation(.easeInOut(duration: 1)){
7 small.toggle()
8 }
9 }
Text with custom animatableModifier - large text is clear
View Extension
The custom modifier can be wrapped in a View Extension to make it easier to use on any Text view and allow for cleaner code.
1extension View {
2 func animatableFont(size: Double,
3 weight: Font.Weight,
4 design: Font.Design = .default) -> some View {
5 self.modifier(AnimatableFontModifier(size: size,
6 weight: weight,
7 design: design))
8 }
9}
1 Text("Size Animated")
2 .animatableFont(size: small ? 24 : 36,
3 weight: small ? .regular : .bold)
4 .frame(width: 350, height: 50, alignment: .leading)
5 .onTapGesture {
6 withAnimation(.easeInOut(duration: 1)){
7 small.toggle()
8 }
9 }
Text with custom animatableFont using View Extension - large text is clear
Conclusion
SwiftUI does not provide a mechanism to animate font size change. This can be added to text views by creating a custom AnimatableModifier using size as the animatableData. The modified can be embedded in a View Extension for easier use in your application code.