Spinner
A customizable loading spinner with smooth animations and multiple visual styles. Perfect for indicating loading states and async operations.
Import
import PrettyUI
Basic Usage
// Simple spinner
PSpinner()
// With label
PSpinner(label: "Loading...")
Sizes
Four sizes are available:
HStack(spacing: 32) {
VStack {
PSpinner().size(.sm)
Text("SM").font(.caption)
}
VStack {
PSpinner().size(.md)
Text("MD").font(.caption)
}
VStack {
PSpinner().size(.lg)
Text("LG").font(.caption)
}
VStack {
PSpinner().size(.xl)
Text("XL").font(.caption)
}
}
| Size | Dimension | Stroke Width | Best For |
|---|---|---|---|
.sm | 16pt | 2pt | Inline, buttons |
.md | 24pt | 2.5pt | Default, cards |
.lg | 32pt | 3pt | Overlays, modals |
.xl | 48pt | 4pt | Full-screen loading |
Styles
Five visual styles are available:
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 24) {
VStack {
PSpinner().size(.lg).style(.circular)
Text("Circular").font(.caption)
}
VStack {
PSpinner().size(.lg).style(.dots)
Text("Dots").font(.caption)
}
VStack {
PSpinner().size(.lg).style(.track)
Text("Track").font(.caption)
}
VStack {
PSpinner().size(.lg).style(.minimal)
Text("Minimal").font(.caption)
}
VStack {
PSpinner().size(.lg).style(.orbit)
Text("Orbit").font(.caption)
}
}
| Style | Description | Best For |
|---|---|---|
.circular | Rotating arc (default) | General purpose |
.dots | Pulsing dots | Inline indicators |
.track | Gradient arc with track | Progress feel |
.minimal | Subtle arc with faint track | Dark backgrounds |
.orbit | Dots in circular orbit | Premium feel |
Custom Colors
Set a custom spinner color:
HStack(spacing: 32) {
PSpinner().size(.lg).primary() // Theme primary
PSpinner().size(.lg).color(.green)
PSpinner().size(.lg).color(.orange)
PSpinner().size(.lg).color(.red)
}
With Labels
Add descriptive text:
// Label below (default)
PSpinner(label: "Loading...")
.size(.lg)
// Label to the right
PSpinner(label: "Please wait")
.size(.md)
.labelPlacement(.trailing)
Label Placement
PSpinner(label: "Loading...")
.labelPlacement(.bottom) // Below spinner (default)
PSpinner(label: "Loading...")
.labelPlacement(.trailing) // Right of spinner
Spinner Overlay
Use the .spinnerOverlay() modifier to show a loading state over content:
PCard {
VStack(spacing: 12) {
Text("Card Content")
.font(.headline)
Text("This card has a loading state")
.font(.caption)
.foregroundColor(.secondary)
}
.padding(.vertical, 24)
}
.spinnerOverlay(isLoading, size: .lg)
Overlay Options
.spinnerOverlay(
isLoading, // Boolean binding
size: .lg, // Spinner size
dimBackground: true // Dim content when loading
)
Real-World Examples
Button Loading State
@State private var isLoading = false
PButton(isLoading ? "Loading..." : "Submit") {
isLoading = true
// ... async operation
}
.loading(isLoading)
Full-Screen Loading
ZStack {
ContentView()
.opacity(isLoading ? 0.3 : 1)
if isLoading {
PSpinner(label: "Loading wallet...")
.size(.xl)
.style(.track)
}
}
Inline Loading
HStack {
Text("Syncing")
PSpinner()
.size(.sm)
.color(.secondary)
}
List Loading State
PList("Transactions") {
if isLoading {
HStack {
Spacer()
PSpinner(label: "Loading transactions...")
.size(.md)
Spacer()
}
.padding(.vertical, 32)
} else {
ForEach(transactions) { transaction in
TransactionRow(transaction)
}
}
}
Refresh Indicator
ScrollView {
LazyVStack {
if isRefreshing {
PSpinner()
.size(.md)
.style(.minimal)
.padding()
}
// Content...
}
}
Style Comparison
Circular vs Track
Use circular for general loading states:
PSpinner().style(.circular)
Use track when you want to convey progress:
PSpinner().style(.track)
Minimal vs Orbit
Use minimal on dark backgrounds or when you want subtlety:
PSpinner().style(.minimal)
Use orbit for a premium, distinctive feel:
PSpinner().style(.orbit)
API Reference
PSpinner Initializer
PSpinner(label: String? = nil)
Modifiers
| Modifier | Type | Description |
|---|---|---|
.size(_:) | PSpinnerSize | Set the spinner size |
.style(_:) | PSpinnerStyle | Set the visual style |
.color(_:) | Color | Set custom color |
.primary() | — | Use theme primary color |
.label(_:) | String? | Set label text |
.labelPlacement(_:) | LabelPlacement | Label position |
View Modifier
.spinnerOverlay(
_ isLoading: Bool,
size: PSpinnerSize = .md,
dimBackground: Bool = true
)
Enums
PSpinnerSize
.sm— 16pt.md— 24pt (default).lg— 32pt.xl— 48pt
PSpinnerStyle
.circular— Rotating arc (default).dots— Pulsing dots.track— Gradient arc with track.minimal— Subtle arc.orbit— Orbital dots
LabelPlacement
.bottom— Label below spinner (default).trailing— Label to the right
Accessibility
PSpinner automatically:
- Respects reduced motion preferences (slower, simpler animations)
- Uses theme colors for consistent appearance
- Provides smooth, non-jarring animations