The Loading Indicator package for UIKit projects provides enhanced control over loading indicators, offering globally configurable settings for a seamless user experience. It allows developers to easily customize and manage loading states across the entire application, ensuring consistent and efficient UI behavior.
To install LoadingIndicatorSwift using Swift Package Manager you can follow the tutorial published by Apple using the URL for the LoadingIndicatorSwift repo with the current version:
- In Xcode, select “File” → “Add Packages...”
- Enter https://github.com/sagark1138/loading-indicator-swift
or you can add the following dependency to your Package.swift
:
.package(url: "https://github.com/sagark1138/loading-indicator-swift", from: "1.0.1")
Step 1: Import the package
import LoadingIndicatorSwift
Step 2: Declare the loading indicator
let loadingIndicator = LoadingIndicator()
Step 3: Add the loading indicator to the view hierarchy, lets add in the root view,
💡 **Note** that, default indicator style is ‘indicator’ which will display only indicator view excluding message and background container view.loadingIndicator.add(in: view)
Step 4: Bind loading indicator to show or hide when the state changes
var isLoading: Bool = false {
didSet {
loadingIndicator.isLoading = isLoading
}
}
A loading indicator with default configurations will be display,
- An overlay over the screen
- An indicator which is system activity indicator, and have medium size with grey foreground color
Preview
default_loading.mov
Using action (iOS 14+)
override func viewDidLoad() {
super.viewDidLoad() {
...
loadingIndicator.onValueChanged { isLoading in
print("Loading value changed: \(isLoading)")
}
...
}
Using selectors
override func viewDidLoad() {
super.viewDidLoad() {
...
loadingIndicator.addTarget(self, action: #selector(loadingValueChanged), for: .valueChanged)
...
}
@objc func loadingValueChanged(sender: LoadingIndicator) {
print(sender.isLoading)
}
Always update loading indicator configurations before adding into parent view to prevent any UI issues.
// 1
loadingIndicator.configuration = .standard.copyWith(
indicator: .standard.copyWith(
foregroundColor: .red,
size: .large
)
)
// 2
loadingIndicator.add(in: view)
Preview
inidcator_size_color.mov
There are 4 available sizes:
- Small : Provides size with width and height of 24 pts
- Medium: Provides size with width and height of 34 pts
- Large: Provides size with width and height of 44 pts
- Custom: Provides custom provided size
Example:
loadingIndicator.configuration = .standard.copyWith(
indicator: .standard.copyWith(
foregroundColor: .red,
size: .custom(size: CGSize(width: 100, height: 100))
)
)
loadingIndicator.overlayColor = .systemBlue.withAlphaComponent(0.2)
Preview
overlay_color.mov
Step 1: Set style of loading indicator white adding in parent view
loadingIndicator.add(in: view, style: .indicator_message)
Step 2: Set message to loading indicator
loadingIndicator.message = "Loading..."
Preview
indicator_message.mov
loadingIndicator.configuration = .standard.copyWith(
message: .standard.copyWith(
color: .systemOrange,
font: .boldSystemFont(ofSize: 16)
)
)
Preview
message_with_font_and_color.mov
loadingIndicator.configuration = .standard.copyWith(
message: .standard.copyWith(
position: .right
)
)
Preview
message_position.mov
loadingIndicator.configuration = .standard.copyWith(
message: .standard.copyWith(
spacing: 10
)
)
Preview
message_spacing.mov
Set style of loading indicator white adding in parent view
loadingIndicator.add(in: view, style: .indicator_message_container)
Preview
container_default_style.mov
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
background: .orange,
corner: .rounded(all: 20)
)
)
Preview
container_bgColor_corner.mov
There are 4 options available to configure corners:
- None : For no corners radius
- Rounded: Round all corners with specified radius
- Edge: Round specified corners with specified radius
- Capsule: Round corners as capsule
Example:
// Edge
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
corner: .edge(corners: [.topLeft, .bottomRight], radius: 16)
)
)
// Rounded
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
corner: .rounded(all: 20)
)
)
// Capsule
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
corner: .capsule
)
)
// None
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
corner: Corner.none // Use type to prevent warnings
)
)
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
padding: .init(all: 20)
)
)
Preview
container_padding.mov
Below example shows all 3 options to configure padding.
// All side
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
padding: .init(all: 20)
)
)
// Edge insets
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
padding: .init(
edgeInsets: UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20)
)
)
)
// Symmetric
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
padding: .init(horizontal: 20, vertical: 10)
)
)
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
border: .init(color: .systemRed, width: 2),
)
)
Preview
container_border.mov
loadingIndicator.configuration = .standard.copyWith(
container: .standard.copyWith(
shadow: .init(
color: .systemTeal,
offset: .init(width: 0, height: 4),
radius: 8,
opacity: 0.3
),
)
)
Preview
container_shadow.mov
Step 1: Add dependency of package Lotte for iOS in your project
Step 2: Download any Lottie animation file and place it inside your projects root bundle
Step 3: Create a new file ‘LottieIndicatorView’ and paste below code inside the file
import UIKit
import Lottie
// 1
class LottieIndicatorView: BaseIndicatorView {
// 2
private lazy var lottieView: LottieAnimationView = {
let lottieView = LottieAnimationView(name: "send_animation")
lottieView.translatesAutoresizingMaskIntoConstraints = false
lottieView.loopMode = .loop
lottieView.contentMode = .scaleAspectFit
return lottieView
}()
// 3
override func setup() {
super.setup()
addSubview(lottieView)
// IMPORTANT: Add constraints to the lottieView
// eg.
lottieView.add(parent: self, fit: .fill)
}
// 4
override func start() {
lottieView.play()
}
// 5
override func stop() {
lottieView.stop()
}
}
- Conform to BaseIndicatorView to override its behavior.
- Create a Lottie animation view.
- Override the setup method and configure Lottie animation view layouts. It's essential to add constraints to the animation view.
- Override the start method and play the animation within it.
- Override the stop method and halt the animation within it.
Step 3: Update indicator configurations by setting a LottieIndicatorView instance to 'view' and adjusting the size to fit the animation.
loadingIndicator.configuration = .standard.copyWith(
indicator: .standard.copyWith(
view: LottieIndicatorView(),
size: .custom(size: CGSize(width: 300, height: 300))
)
)
Preview
lottie_indicator.mov
That's it, it's ready to use.
The Lottie animation will now be seamlessly integrated into your loading indicator, providing a visually appealing and customized experience for users. This approach allows for greater flexibility in designing loading indicators that match your app's aesthetic and enhance user engagement during wait times.
Step 1: Create a new file ‘CustomViewIndicator’ and paste below code inside the file
import UIKit
// 1
class CustomViewIndicator: BaseIndicatorView {
// 2
override var foregroundColor: UIColor {
didSet {
backgroundColor = foregroundColor
}
}
// 3
override func setup() {
super.setup()
round(corners: [.bottomLeft, .topRight], radius: 60)
backgroundColor = foregroundColor
}
// 4
override func start() {
rotate360Degrees()
}
// 5
override func stop() {
layer.removeAllAnimations()
}
}
extension UIView {
func rotate360Degrees(duration: CFTimeInterval = 3) {
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = CGFloat(Double.pi * 2)
rotateAnimation.isRemovedOnCompletion = false
rotateAnimation.duration = duration
rotateAnimation.isCumulative = true
rotateAnimation.speed = 2.0
rotateAnimation.repeatCount = Float.infinity
self.layer.add(rotateAnimation, forKey: nil)
}
}
- Conform to BaseIndicatorView to override its behavior.
- Override the setup method to configure the current view, setting the background color and applying corner radius to specific edges.
- Override the start method to initiate the animation.
- Override the stop method to halt the animation.
Step 2: Update indicator configurations by setting a CustomViewIndicator instance to 'view' and adjusting the size to fit the animation.
loadingIndicator.configuration = .standard.copyWith(
indicator: .standard.copyWith(
view: CustomViewIndicator(),
size: .custom(size: CGSize(width: 100, height: 100))
)
)
Preview
custom_indicator.mov
That's it, it's ready to use.
This custom rotating view indicator provides a simple yet visually appealing animation for your loading indicator. By implementing this custom view, you can create a unique loading experience that aligns with your app's design language. Remember to adjust the size, colors, and animation duration as needed to best fit your specific use case.