1 minute read

Animating UI elements with UIView.animate in Swift

Motion gives an interface a sense of cause and effect. A button can grow when pressed, a card can fade into view, and a panel can slide into place without confusing the person using it. UIView.animate is UIKit’s simplest tool for these changes, but useful motion depends on timing, interruption and accessibility.

On crowded trains in Melbourne and Sydney, people often check an iPhone for only a few seconds. A transition that lags or a control that appears frozen can therefore be noticed quickly. Small animations should confirm an action, explain where something came from and then get out of the way.

I’m Askar Almukhamet, an iOS developer from Atyrau, Kazakhstan, and I use small UIKit experiments to learn how Apple frameworks behave. This article covers the mechanics behind those experiments: changing view properties, choosing a duration, handling completion and testing the result in Xcode with Swift.

Choosing motion that explains change

Start with the meaning of the change rather than the animation curve. A confirmation state usually needs a brief scale or colour change. A view entering from outside the screen needs enough movement to establish direction, while a loading indicator needs continuous repetition rather than a one-off transition. Good motion answers a question such as “did that register?” or “where did this panel come from?”

The animation closure describes the destination state. UIKit interpolates the relevant properties between their current and final values over the specified duration. For a small control, durations around 0.2 to 0.3 seconds often feel direct. A larger panel may justify 0.35 to 0.5 seconds, although longer does not automatically mean clearer.

This API has a useful division of labour: you provide the final values and UIKit manages the visual transition. It does not make every property animatable, prevent an interruption or automatically adapt custom movement to accessibility settings. Those decisions remain part of your implementation.

Animating transforms, colour and alpha

Common animatable UIView properties include frame, bounds, centre, alpha, background colour and transform. Transforms are particularly useful because they can change apparent size or position without altering the view’s Auto Layout constraints.

UIView.animate(withDuration: 0.25) {
    button.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
    button.backgroundColor = .systemPink
}

A transform is relative to the view’s current transform, so successive scale changes can accumulate. Returning to CGAffineTransform.identity resets scale, rotation and translation together. For a repeatable press effect, animate back to identity or preserve the intended transform. Alpha works in the same closure, but a completely transparent view still receives touches unless user interaction is disabled.

Laying out views inside an animation

With Auto Layout, animate a constraint’s constant rather than setting a frame that the layout engine will later replace. Inside the animations closure, change the constant and call layoutIfNeeded() so UIKit can calculate the intermediate positions.

UIView.animate(withDuration: 0.3) {
    self.heightConstraint.constant = 220
    self.view.layoutIfNeeded()
}

If pending layout needs to be resolved before the animation, call layoutIfNeeded() beforehand. The call inside the closure exposes the destination layout for interpolation. For a manually laid-out view, animating frame or bounds is valid, but avoid mixing frame manipulation with active constraints that will immediately replace it.

Timing curves and spring behaviour

Short, predictable motion suits controls, while a spring can make an element appear physical. A damping ratio of 1 creates a critically damped spring without oscillation. Values below 1 introduce overshoot, while a larger initial velocity gives the movement more energy from its beginning.

UIView.animate(
    withDuration: 0.55,
    delay: 0,
    usingSpringWithDamping: 0.72,
    initialSpringVelocity: 0.4,
    options: [.allowUserInteraction],
    animations: {
        card.transform = CGAffineTransform(translationX: 0, y: -12)
    }
)

The spring’s duration parameter is not the exact moment its final movement ends, so judge the result by feel rather than assuming the completion handler matches the visible settling time. The .allowUserInteraction option is also useful when the animated view must continue responding to touches during the transition.

Handling interruption and completion

Real interaction can interrupt an animation. A user might tap a control again, drag a sheet or navigate away while a transition is running. The .beginFromCurrentState option helps a replacement animation start from the current visual position rather than snapping to an outdated endpoint.

UIView.animate(
    withDuration: 0.3,
    delay: 0,
    options: [.beginFromCurrentState],
    animations: {
        self.panel.transform = .identity
    },
    completion: { finished in
        guard finished else { return }
        self.statusLabel.text = "Panel closed"
    }
)

The completion handler runs whether the animation finishes naturally or gets interrupted. Its Boolean argument reports which happened, so do not treat every completion as success. UIView.animate returns no progress value and cannot be paused; use UIViewPropertyAnimator when you need pausing, reversal or manual scrubbing.

Prototyping and measuring in Xcode

A playground is enough for a first UIKit experiment. Its live results let you compare duration, spring damping and repeated taps without designing an entire screen. Keep the example in one file so the animated property and its trigger remain easy to find.

In an app target, Xcode’s Debug View Hierarchy and View Debugger reveal frames, constraints and the final layout. The assistant editor can show effects beside the code, while breakpoint logging can reveal whether an animation closure runs more than once. The Animation Hitches instrument in Instruments highlights frames that miss their expected display time. Test on a physical iPhone as well as the simulator, particularly when motion accompanies scrolling, gestures or controller presentation.

Respecting accessibility and Australian expectations

Custom motion needs an accessibility check. UIKit reduces some standard transitions when Reduce Motion is enabled, but not every custom UIView.animate call is adapted automatically. Use UIAccessibility.isReduceMotionEnabled to choose an immediate state change or restrained fade instead of large movement, while preserving the same final state.

VoiceOver, Dynamic Type and sufficient contrast still matter during a transition. Keep the animated control labelled and understandable when motion is unavailable.

Australian legal and market expectations reinforce that discipline. The Australian Consumer Law, part of the Competition and Consumer Act 2010, sets consumer guarantees for goods and services, making dependable behaviour more important than decorative movement. The Disability Discrimination Act 1992 also makes accessibility a relevant consideration for many Australian services. Clear rules matter across the local market too, as coverage of Bitcoin casino legality illustrates; plain Australian English and readable controls are the everyday equivalents.


The value of UIView.animate is not that it creates elaborate effects. A small, well-timed state change can make an interface feel responsive, while transforms provide a reversible way to test that idea. Springs add physical character, and completion handlers reveal what happened when real interaction interrupts the ideal path.

The next concrete step is to create a UIKit playground in Xcode and animate one square from a scale of 1.0 to 1.2, then back to identity, when it is tapped.

Updated: