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
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
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
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
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.