How do UIView.animate, UIViewPropertyAnimator and SwiftUI’s animations relate, and when do you pick each?
Predict first
Which states does a property animator pass through as it is started, paused and finished?
import UIKit
let w = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
w.makeKeyAndVisible()
let v = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
w.addSubview(v)
let pa = UIViewPropertyAnimator(duration: 1, curve: .easeInOut) { v.alpha = 0.2 }
print(pa.state.rawValue, pa.isRunning)
pa.startAnimation()
print(pa.state.rawValue, pa.isRunning)
pa.pauseAnimation()
print(pa.state.rawValue, pa.isRunning)
pa.stopAnimation(false)
print(pa.state.rawValue)
pa.finishAnimation(at: .end)
print(pa.state.rawValue)
- 0 false, 1 true, 1 false, 2, 0
- 0 false, 1 true, 2 false, 2, 0
- 1 false, 1 true, 1 false, 0, 0
Mental model. UIView.animate presses “play” on a pre-recorded clip. A property animator is a remote with pause and scrub, so the user can drag the timeline. SwiftUI hands the director a before and after picture and lets the studio fill in the frames.
UIView.animate(withDuration:…) (and its spring, keyframe and transition variants) is the simplest: set the end state inside the closure, and UIKit creates the Core Animation animations. It is fire-and-forget: no pause, no scrubbing, and a completion closure with a finished flag (false if it was interrupted). UIViewPropertyAnimator gives a controllable object: startAnimation(), pauseAnimation(), fractionComplete to scrub, isReversed, stopAnimation(_:), finishAnimation(at:), and the ability to add animations and completions after creating it. It is the tool for interactive and interruptible animations: a drag that scrubs a transition, a card the user can grab mid-flight. It moves through states: inactive, active and stopped; and a paused animator has isRunning false but is still active. When you stop it you must finish it, or it leaks and is left in an odd state.
The two models differ from SwiftUI’s. UIKit animation is imperative and event-based: you start an animation at a moment, say what to animate in a closure, and UIKit adds animations to layers. SwiftUI animation is declarative and state-based: you change state inside a transaction, and SwiftUI interpolates the difference between the old and new description of the view (it carries the animation in the Transaction; see the SwiftUI animation question). SwiftUI’s withAnimation corresponds to wrapping the change in UIView.animate, and .animation(_:value:) to animating a specific change. For interactive scrubbing, UIViewPropertyAnimator is still the UIKit tool, and SwiftUI uses gestures plus state with spring animations. Whichever you use: keep animations short, prefer springs, honour Reduce Motion (UIAccessibility.isReduceMotionEnabled), and avoid animating layout-heavy properties on huge hierarchies.
Inactive (0) before starting, active (1) while running or paused, stopped (2) after stopAnimation, and back to inactive (0) once finished.
| UIView.animate | UIViewPropertyAnimator | SwiftUI withAnimation | |
|---|---|---|---|
| Model | imperative closure | imperative, controllable object | declarative, state-based |
| Interruptible, scrub | no | yes | by gesture and state |
| Result | animations on layers | animations on layers | interpolated view description |
Common traps
- Leaving a stopped
UIViewPropertyAnimatorwithout finishing it. It must be finished, or its state and views are left inconsistent. - Treating the completion’s
finishedas always true. It is false if the animation was cancelled or interrupted.
They might follow up with
- Which API for a swipe that scrubs a transition?
UIViewPropertyAnimator, withfractionComplete. - How does SwiftUI’s
withAnimationcompare? It sets the animation in the transaction for the state change, much like wrapping it inUIView.animate.
Related questions
- 9.4.1 How do implicit and explicit animations differ in Core Animation, and how does CATransaction fit in?
- 8.7.1 What is the difference between implicit and explicit animation, and how do transitions fit in?
- 7.3.4 How do you build a custom view controller transition, including an interactive one?
← How do implicit and explicit animations differ in Core Animation, and…