A protocol-driven SwiftUI badge component for displaying progress, status, and state transitions with smooth animations.
- Protocol-based states —
BoneBadgeStatelets you define custom badge states with icons, text, progress, and default styling - Protocol-based styles —
BoneBadgeStylecontrols rendering, injected via SwiftUI environment - Animated transitions — smooth state-to-state animations with SF Symbol effects (
.replace,.drawOn/.drawOff, variable value) - Progress color interpolation — configurable multi-stop color progressions with progressive, hard, or gradient transitions
- Luminance-aware text — auto-selects light/dark text based on bar fill color
- Flexible sizing — automatic, hugging, fixed, min/max width, fill, and range modes
| State | Description |
|---|---|
ReadyBadgeState |
Blue capsule with optional arrow icon |
InProgressBadgeState |
Progress bar with percentage text |
CompletedBadgeState |
Green capsule with checkmark icon |
SpinnerBadgeState |
Animated loading indicator |
CustomBadgeState |
Fully configurable state |
| Style | Description |
|---|---|
DefaultBadgeStyle |
Transparent background (for state badges) |
PillBadgeStyle |
Compact pill with colored fill |
BarBadgeStyle |
Full-width bar with split-color text |
OnBarBadgeStyle |
Bar with text rendered on the filled portion |
SpinnerBadgeStyle |
Transparent background with animated icon effects |
CircularProgressBadgeStyle |
Circular ring using SF Symbol variable value |
Add BoneBadge to your project using Swift Package Manager:
dependencies: [
.package(url: "https://github.com/allogy/BoneBadge.git", from: "1.0.0")
]import BoneBadge
// Progress bar (default bar style)
BoneBadge(state: .inProgress(0.65))
// Pill style
BoneBadge(state: .inProgress(0.65))
.boneBadgeStyle(.pill)
// On-bar style with compact overflow
BoneBadge(state: .inProgress(0.65, shortText: true))
.boneBadgeStyle(.onBar(overflow: .compact))// Ready state
BoneBadge(state: .ready)
// Completed state
BoneBadge(state: .completed)
// Spinner (loading)
BoneBadge(state: .spinner)
// Custom state
BoneBadge(
state: .custom,
text: "Custom Badge",
configuration: BoneBadgeConfiguration(
iconName: "star.fill",
backgroundColor: Color.purple.opacity(0.18),
textColor: .purple
)
)BoneBadge(
state: .inProgress(0.50),
configuration: BoneBadgeConfiguration(
font: .subheadline.weight(.bold),
edgeStyle: .roundedRect(cornerRadius: 8),
barEdgeStyle: .matchIndicator,
borderWidth: 2,
highlightStyle: .alpha(),
progressColors: [.red, .green],
colorTransitionMode: .gradient
)
)VStack {
BoneBadge(state: .inProgress(0.25))
BoneBadge(state: .inProgress(0.75))
}
.boneBadgeStyle(.onBar())Conform to BoneBadgeState to create your own:
struct DownloadingState: BoneBadgeState {
let percent: Double
var iconName: String? { "arrow.down.circle.fill" }
var displayText: String? { "\(Int(percent * 100))% Complete" }
var progress: Double? { percent }
var defaultConfiguration: BoneBadgeConfiguration { .progress }
var defaultStyle: AnyBoneBadgeStyle { AnyBoneBadgeStyle(BarBadgeStyle()) }
}Conform to BoneBadgeStyle to create your own:
struct MyCustomStyle: BoneBadgeStyle {
var rendersOwnText: Bool { true }
var expandsToFillWidth: Bool { true }
func makeBody(in context: BoneBadgeStyleContext) -> some View {
// Your custom rendering using context.progress, context.size, etc.
}
}- iOS 18.0+
- Swift 6.2+
- Xcode 16+
BSD 3-Clause License. See LICENSE for details.