Skip to content

AnimatableModifier (SwiftUI)

A SwiftUI guide for coding agents. Also covers animate number counter, animatabledata, animatable text, custom animatable modifier, count up animation ios.

A plain ViewModifier cannot animate its own behavior, and conforming it to Animatable alone does nothing. AnimatableModifier combines the two protocols so SwiftUI re-runs the modifier's body on every animation frame, which animates things SwiftUI cannot animate by itself, such as the digits in a text view. Available since iOS 13.

Animating a Number

Expose the value to interpolate through animatableData. SwiftUI drives that property through the animation curve and calls body with each intermediate value.

struct NumberView: AnimatableModifier {
  var number: Int

  var animatableData: CGFloat {
    get { CGFloat(number) }
    set { number = Int(newValue) }
  }

  func body(content: Content) -> some View {
    Text(String(number))
  }
}

The content parameter is usually what a modifier decorates; here the modifier ignores it and returns a fresh Text each frame, because the text itself is what changes.

Driving It

Mutate the state inside withAnimation as usual. The count-up effect comes entirely from the interpolation of animatableData.

struct ContentView: View {
  @State private var number = 0

  var body: some View {
    VStack {
      Text(String(number))
        .modifier(NumberView(number: number))

      Button("Animate") {
        withAnimation(.easeInOut(duration: 2)) {
          number = 100
        }
      }
    }
  }
}

animatableData must be a VectorArithmetic type such as CGFloat or AnimatablePair; convert integers at the boundary as above. On newer SDKs AnimatableModifier is deprecated in favor of conforming a ViewModifier to Animatable directly, and the animatableData pattern is unchanged.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-animatablemodifier" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems