UIActivityIndicatorView
UIActivityIndicatorView is a UIKit control that displays a spinning indicator to show that a task is in progress, such as loading data or performing a network request. It is a subclass of UIView and is commonly used to provide visual feedback during asynchronous operations. This document covers the key properties, methods, and usage of UIActivityIndicatorView, along with examples and best practices.
Overview of UIActivityIndicatorView
A UIActivityIndicatorView is a simple, lightweight control that animates a spinning wheel or similar indicator. It is ideal for indicating ongoing activity without specifying progress (unlike UIProgressView). The control supports different styles and can be customized for color and behavior.
Creating a UIActivityIndicatorView
You can create a UIActivityIndicatorView programmatically or via Interface Builder (storyboards/xibs).
Programmatic Example:
import UIKit
let activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.color = .systemBlue
activityIndicator.startAnimating()
view.addSubview(activityIndicator)Key Properties of UIActivityIndicatorView
Below are the most commonly used properties of UIActivityIndicatorView:
| Property | Type | Description |
|---|---|---|
style | UIActivityIndicatorView.Style | The visual style of the indicator (e.g., .medium, .large). |
color | UIColor? | The color of the spinning indicator. |
isAnimating | Bool | Indicates whether the indicator is currently animating (read-only). |
hidesWhenStopped | Bool | If true, the indicator is hidden when not animating. |
activityIndicatorViewStyle | UIActivityIndicatorView.Style | Deprecated in iOS 13; use style instead. |
Available Styles (iOS 13+)
.medium: A standard-sized indicator, suitable for most use cases..large: A larger indicator for more prominent display.
Pre-iOS 13 Styles (Deprecated):
.gray: A gray-colored indicator..white: A white indicator..whiteLarge: A larger white indicator.
Example: Configuring Properties:
activityIndicator.style = .large
activityIndicator.color = .systemGreen
activityIndicator.hidesWhenStopped = trueKey Methods of UIActivityIndicatorView
UIActivityIndicatorView inherits methods from UIView, but also provides methods specific to animation control:
| Method | Description |
|---|---|
startAnimating() | Starts the spinning animation. |
stopAnimating() | Stops the spinning animation (hides the view if hidesWhenStopped is true). |
isAnimating | Returns true if the indicator is animating. |
Example: Controlling Animation:
activityIndicator.startAnimating() // Start spinning
activityIndicator.stopAnimating() // Stop spinningCustomizing Appearance
Color
Set the color property to change the indicator’s tint.
Example:
activityIndicator.color = .systemRedHiding When Stopped
Set hidesWhenStopped to true to automatically hide the indicator when it stops animating.
Example:
activityIndicator.hidesWhenStopped = true
activityIndicator.stopAnimating() // Indicator is hiddenSize and Style
Choose .medium or .large based on the context. The indicator’s size is fixed for each style, but you can adjust its position using Auto Layout or frames.
Using UIActivityIndicatorView
Typical Use Case
Show the indicator during a task (e.g., network request) and hide it when the task completes.
Example:
func fetchData() {
activityIndicator.startAnimating()
// Simulate async task
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.activityIndicator.stopAnimating()
}
}Combining with Other UI Elements
Pair the indicator with a label or overlay to provide context.
Example:
let label = UILabel()
label.text = "Loading..."
view.addSubview(label)
view.addSubview(activityIndicator)
label.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(view.safeAreaLayoutGuide).offset(20)
}
activityIndicator.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(label.snp.bottom).offset(10)
}Best Practices
Use Sparingly: Display the indicator only during active tasks to avoid visual clutter.
Support Accessibility: Set
accessibilityLabelandaccessibilityTraitsfor VoiceOver.swiftactivityIndicator.accessibilityLabel = "Loading indicator" activityIndicator.accessibilityTraits = .updatesFrequentlyUse Auto Layout: Set
translatesAutoresizingMaskIntoConstraints = falseand use constraints (e.g., with SnapKit).Provide Context: Pair with a label or other UI element to clarify what is loading.
Test on Devices: Verify appearance and animation on various screen sizes and iOS versions.
Troubleshooting
- Indicator Not Showing: Ensure
startAnimating()is called and the view is added to the view hierarchy. - Indicator Not Hiding: Check if
hidesWhenStoppedistrueandstopAnimating()is called. - Appearance Issues: Verify
styleandcolorcompatibility with the iOS version. - Accessibility Issues: Test with VoiceOver to ensure proper feedback.
Example: Complete UIActivityIndicatorView Setup
import UIKit
import SnapKit
class ViewController: UIViewController {
let activityIndicator = UIActivityIndicatorView(style: .large)
let statusLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// Configure activity indicator
activityIndicator.color = .systemBlue
activityIndicator.hidesWhenStopped = true
activityIndicator.accessibilityLabel = "Loading indicator"
// Configure label
statusLabel.text = "Tap to Load"
statusLabel.textAlignment = .center
view.addSubview(activityIndicator)
view.addSubview(statusLabel)
// Auto Layout with SnapKit
statusLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalToSuperview().offset(-20)
}
activityIndicator.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(statusLabel.snp.bottom).offset(10)
}
// Add tap gesture to simulate loading
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(startLoading))
view.addGestureRecognizer(tapGesture)
}
@objc func startLoading() {
statusLabel.text = "Loading..."
activityIndicator.startAnimating()
// Simulate async task
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.activityIndicator.stopAnimating()
self.statusLabel.text = "Loaded!"
}
}
}