A customizable animated gradient loading bar, with full support for SwiftUI and UIKit.
Inspired by iOS 7 Progress Bar on CodePen.
To run the example project, clone this repository and open the project file from the Example directory.
- Swift 6.2
- Xcode 26
- iOS 26.0+
- iOS < 26.0 / CocoaPods / Carthage support
Use version3.x.x - iOS < 13.0 support
Use version2.x.x
Gradient Loading Bar is distributed via Swift Package Manager (SPM). Add it to your Xcode project as a package dependency or adapt your Package.swift file.
- Open your project in Xcode
- Go to File → Add Packages…
- Enter the package URL:
https://github.com/fxm90/GradientLoadingBar - Choose the version rule (e.g. Up to Next Major starting at 4.0.0)
- Add the package to your target
If you manage dependencies manually, add this repository to the dependencies section of your Package.swift:
dependencies: [
.package(
url: "https://github.com/fxm90/GradientLoadingBar",
from: "4.0.0"
)
]Then reference the product in your target configuration:
.product(
name: "GradientLoadingBar",
package: "GradientLoadingBar"
)Once the package is added, import the framework where needed:
import GradientLoadingBarThis framework provides four types:
-
GradientLoadingBar
A controller class, managing the visibility of theGradientActivityIndicatorViewattached to the current key window. -
NotchGradientLoadingBar
A subclass ofGradientLoadingBar, wrapping theGradientActivityIndicatorViewaround the iPhone notch. -
GradientActivityIndicatorView
AUIViewcontaining the gradient with the animation. -
GradientLoadingBarView
A SwiftUIViewcontaining the gradient with the animation.
GradientLoadingBar is a controller-style object that manages a gradient loading bar attached to the app’s key window.
For most use cases, prefer the shared instance provided by GradientLoadingBar.shared.
final class UserProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
GradientLoadingBar.shared.fadeIn()
userProfileService.fetchUserProfile { _ in
// ...
// Be sure to call this from the main actor!
GradientLoadingBar.shared.fadeOut()
}
}
}This shared instance can be overridden to customize the loading bar globally.
let gradientLoadingBar = GradientLoadingBar(
height: 5.0,
isRelativeToSafeArea: false,
)
gradientLoadingBar.gradientColors = [.systemIndigo, .systemPurple, .systemPink]
gradientLoadingBar.progressAnimationDuration = 4.5-
height: CGFloat
Sets the bar height (default:3.0) -
isRelativeToSafeArea: Bool
Determines whether the bar is positioned relative to the safe area (default:true)
| Relative To Safe Area | Ignoring Safe Area |
|---|---|
The gradient animation is easier to see in a video of the example application:
🎬 Relative To Safe Area
relative-to-safe-area.mov
🎬 Ignoring Safe Area
ignoring-safe-area.mov
Note: For a third option — wrapping around the iPhone notch — see NotchGradientLoadingBar.
-
gradientColors: [UIColor]
Defines the gradient colors. -
progressAnimationDuration: TimeInterval
Controls how fast the gradient animates from left to right.
-
fadeIn(duration: TimeInterval = 0.33, completion: ((Bool) -> Void)? = nil)
Fades the loading bar in. -
fadeOut(duration: TimeInterval = 0.66, completion: ((Bool) -> Void)? = nil)
Fades the loading bar out.
NotchGradientLoadingBar is a subclass of GradientLoadingBar that wraps the bar around the iPhone notch.
On devices without a notch, it behaves identically to GradientLoadingBar.
| iPhone 12 Pro | iPhone 13 Pro Max |
|---|---|
The gradient animation is easier to see in a video of the example application:
🎬 iPhone 12 Pro
notch-iphone-12-pro.mov
🎬 iPhone 13 Pro Max
notch-iphone-13-pro-max.mov
If you prefer direct view composition, GradientActivityIndicatorView is a UIView subclass that can be added to other views — such as UINavigationBar, UIButton or a custom container.
Store an instance as a property, set-up constraints and control the visibility using fadeIn() and fadeOut().
final class UserProfileViewController: UIViewController {
private let gradientActivityIndicatorView = GradientActivityIndicatorView()
// ...
override func viewDidLoad() {
super.viewDidLoad()
gradientActivityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(gradientActivityIndicatorView)
NSLayoutConstraint.activate([
gradientActivityIndicatorView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
gradientActivityIndicatorView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
gradientActivityIndicatorView.topAnchor.constraint(equalTo: view.topAnchor),
gradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: 3),
])
gradientActivityIndicatorView.fadeIn()
userProfileService.fetchUserProfile { [weak self] _ in
// ...
// Be sure to call this from the main actor!
self?.gradientActivityIndicatorView.fadeOut()
}
}
}let gradientActivityIndicatorView = GradientActivityIndicatorView()
gradientActivityIndicatorView.gradientColors = [.systemIndigo, .systemPurple, .systemPink]
gradientActivityIndicatorView.progressAnimationDuration = 4.5-
isHidden: Bool
Toggles the view visibility and starts / stops the progress animation accordingly. -
gradientColors: [UIColor]
Defines the gradient colors. -
progressAnimationDuration: TimeInterval
Controls how fast the gradient animates from left to right.
-
fadeIn(duration: TimeInterval = 0.33, completion: ((Bool) -> Void)? = nil)
Fades the view in. -
fadeOut(duration: TimeInterval = 0.66, completion: ((Bool) -> Void)? = nil)
Fades the view out. -
animate(isHidden: Bool, duration: TimeInterval, completion: ((Bool) -> Void)? = nil)
Fades the view in- or out, based on the provided hidden flag.
GradientLoadingBarView is the SwiftUI equivalent of GradientActivityIndicatorView.
struct ContentView: some View {
var body: some View {
GradientLoadingBarView()
.frame(maxWidth: .infinity, maxHeight: 3)
.cornerRadius(1.5)
}
}GradientLoadingBarView(
gradientColors: [.indigo, .purple, .pink],
progressDuration: 4.5,
)-
gradientColors: [Color]
Defines the gradient colors. -
progressDuration: TimeInterval
Sets the animation speed.
Control the visibility using standard SwiftUI view modifiers such as:
Example with fade animation.
struct ContentView: some View {
@State
private var isVisible = false
var body: some View {
VStack {
GradientLoadingBarView()
.frame(maxWidth: .infinity, maxHeight: 3)
.cornerRadius(1.5)
.opacity(isVisible ? 1 : 0)
.animation(.easeInOut, value: isVisible)
Button("Toggle visibility") {
isVisible.toggle()
}
}
}
}Felix Mau me(@)felix.hamburg
Gradient Loading Bar is released under the MIT License. See the LICENSE file for details.
