UIView
animations
iOS development
Swift
user interface

UIView Hide/Show with animation

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Showing and hiding a UIView with animation is easy to start and easy to get subtly wrong. Common bugs include hidden views intercepting touches, views that never become visible again, and layout jumps during state changes. A robust solution coordinates alpha, isHidden, and Auto Layout updates in a predictable sequence.

Core Visibility Principles

isHidden removes drawing and interaction immediately. alpha animates visual opacity but does not remove the view from layout. Good transitions usually combine both.

Recommended behavior:

  • For show: unhide first, set low alpha, animate to full alpha.
  • For hide: animate alpha to zero, then set hidden in completion block.
swift
1import UIKit
2
3extension UIView {
4    func showAnimated(duration: TimeInterval = 0.25,
5                      curve: UIView.AnimationOptions = .curveEaseInOut,
6                      completion: (() -> Void)? = nil) {
7        if isHidden {
8            alpha = 0
9            isHidden = false
10        }
11
12        UIView.animate(withDuration: duration, delay: 0, options: [curve, .beginFromCurrentState]) {
13            self.alpha = 1
14        } completion: { _ in
15            completion?()
16        }
17    }
18
19    func hideAnimated(duration: TimeInterval = 0.25,
20                      curve: UIView.AnimationOptions = .curveEaseInOut,
21                      completion: (() -> Void)? = nil) {
22        UIView.animate(withDuration: duration, delay: 0, options: [curve, .beginFromCurrentState]) {
23            self.alpha = 0
24        } completion: { _ in
25            self.isHidden = true
26            completion?()
27        }
28    }
29}

This helper is reusable, keeps behavior consistent, and avoids timing mistakes repeated across screens.

Animate Layout and Visibility Together

If the view also moves by constraint changes, animate layoutIfNeeded in the same block.

swift
1import UIKit
2
3final class PanelViewController: UIViewController {
4    @IBOutlet private weak var panel: UIView!
5    @IBOutlet private weak var panelTop: NSLayoutConstraint!
6
7    private var isPanelVisible = false
8
9    @IBAction func togglePanel(_ sender: UIButton) {
10        isPanelVisible.toggle()
11
12        if isPanelVisible {
13            panelTop.constant = 0
14            panel.showAnimated(duration: 0.3)
15        } else {
16            panelTop.constant = -220
17            panel.hideAnimated(duration: 0.3)
18        }
19
20        UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseInOut]) {
21            self.view.layoutIfNeeded()
22        }
23    }
24}

If layout changes and alpha changes are split into unrelated animations, transitions feel broken.

Interaction and Accessibility Considerations

A view with alpha = 0 but isHidden = false can still block touches. For hidden states, always set isHidden = true eventually. For modal-style views, also consider isUserInteractionEnabled during transition phases.

Respect reduced-motion settings for users who prefer minimal animation.

swift
func preferredAnimationDuration() -> TimeInterval {
    return UIAccessibility.isReduceMotionEnabled ? 0.0 : 0.25
}

Using this helper in your show/hide calls keeps interaction inclusive and predictable.

Dealing With Repeated Toggle Calls

Rapid taps can start overlapping animations. Use .beginFromCurrentState and keep one source of truth for visibility.

swift
1private var isAnimating = false
2
3func setVisible(_ visible: Bool) {
4    guard !isAnimating else { return }
5    isAnimating = true
6
7    let done = { [weak self] in self?.isAnimating = false }
8    if visible {
9        panel.showAnimated(completion: done)
10    } else {
11        panel.hideAnimated(completion: done)
12    }
13}

This prevents inconsistent intermediate states during fast user interaction.

Testing Checklist

Use a practical checklist to validate behavior:

  1. Hidden to visible transition keeps final alpha at 1.
  2. Visible to hidden transition sets isHidden = true after fade.
  3. Rapid repeated taps do not leave half-visible states.
  4. Constraint animation remains in sync with fade.
  5. Reduced-motion mode still yields correct final state.

Visual bugs in animation often come from one missed state flag, so checklist testing pays off.

Common Pitfalls

A common pitfall is setting isHidden to true before fade-out begins, which makes animation invisible. Another issue is forgetting to restore alpha to 1 before showing again, leaving the view present but still transparent. Teams also animate on background threads in indirect async callbacks, which can cause undefined UI behavior. In layout-heavy screens, not animating layoutIfNeeded with the same timing as alpha leads to jumpy movement. Finally, repeated toggles without state control can produce stuck views that are visible but non-interactive.

Summary

  • Coordinate alpha and isHidden instead of toggling only one property.
  • Unhide before fade-in and hide only after fade-out completion.
  • Animate constraints and opacity together for smooth transitions.
  • Handle rapid toggles with explicit state guards.
  • Respect reduced-motion settings while preserving final visibility state.

Course illustration
Course illustration

All Rights Reserved.