mirror of
https://github.com/fxm90/GradientLoadingBar.git
synced 2026-06-16 12:24:31 +00:00
✨ :: Add example application
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "tinted"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "512x512"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "512x512"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
TabView {
|
||||
Tab("Basic Example", systemImage: SFSymbol.iPhoneGen3.rawValue) {
|
||||
BasicExampleView()
|
||||
}
|
||||
Tab("Notch Example", systemImage: SFSymbol.iPhoneGen2.rawValue) {
|
||||
NotchExampleView()
|
||||
}
|
||||
Tab("UIKit Example", systemImage: SFSymbol.squareStack.rawValue) {
|
||||
UIKitExampleView()
|
||||
}
|
||||
Tab("SwiftUI Example", systemImage: SFSymbol.swift.rawValue) {
|
||||
SwiftUIExampleView()
|
||||
}
|
||||
}
|
||||
.overlay(alignment: .top) {
|
||||
Text("– Gradient Loading Bar Example –")
|
||||
.font(.caption)
|
||||
.offset(x: 0, y: .space3)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// BasicExampleView.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import GradientLoadingBar
|
||||
import SwiftUI
|
||||
|
||||
/// A basic example view demonstrating the usage of the `GradientLoadingBar`.
|
||||
struct BasicExampleView: View {
|
||||
|
||||
private let relativeToSafeAreaLoadingBar = GradientLoadingBar()
|
||||
private let ignoringSafeAreaLoadingBar = GradientLoadingBar(isRelativeToSafeArea: false)
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: .space6) {
|
||||
VStack(spacing: .space2) {
|
||||
Text("Relative to Safe Area")
|
||||
.font(.headline)
|
||||
|
||||
HStack(spacing: .space2) {
|
||||
Button {
|
||||
relativeToSafeAreaLoadingBar.fadeOut()
|
||||
} label: {
|
||||
Label("Hide", systemImage: SFSymbol.eyeSlash.rawValue)
|
||||
.padding(.space1)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
|
||||
Button {
|
||||
relativeToSafeAreaLoadingBar.fadeIn()
|
||||
} label: {
|
||||
Label("Show", systemImage: SFSymbol.eye.rawValue)
|
||||
.padding(.space1)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
}
|
||||
}
|
||||
|
||||
VStack(spacing: .space2) {
|
||||
Text("Ignores Safe Area")
|
||||
.font(.headline)
|
||||
|
||||
HStack(spacing: .space2) {
|
||||
Button {
|
||||
ignoringSafeAreaLoadingBar.fadeOut()
|
||||
} label: {
|
||||
Label("Hide", systemImage: SFSymbol.eyeSlash.rawValue)
|
||||
.padding(.space1)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
|
||||
Button {
|
||||
ignoringSafeAreaLoadingBar.fadeIn()
|
||||
} label: {
|
||||
Label("Show", systemImage: SFSymbol.eye.rawValue)
|
||||
.padding(.space1)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.space6)
|
||||
.navigationTitle("Basic Example")
|
||||
}
|
||||
.onDisappear {
|
||||
relativeToSafeAreaLoadingBar.fadeOut()
|
||||
ignoringSafeAreaLoadingBar.fadeOut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
|
||||
#Preview {
|
||||
// Previews do not provide a key window, therefore button interactions do not display the loading bar.
|
||||
// To view the loading bar in action, run the example application in the simulator.
|
||||
BasicExampleView()
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// NotchExampleView.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import GradientLoadingBar
|
||||
import SwiftUI
|
||||
|
||||
/// An example view demonstrating the usage of the `NotchGradientLoadingBar`
|
||||
struct NotchExampleView: View {
|
||||
|
||||
private let notchGradientLoadingBar = NotchGradientLoadingBar()
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: .space4) {
|
||||
HStack(spacing: .space2) {
|
||||
Button {
|
||||
notchGradientLoadingBar.fadeOut()
|
||||
} label: {
|
||||
Label("Hide", systemImage: SFSymbol.eyeSlash.rawValue)
|
||||
.padding(.space1)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
|
||||
Button {
|
||||
notchGradientLoadingBar.fadeIn()
|
||||
} label: {
|
||||
Label("Show", systemImage: SFSymbol.eye.rawValue)
|
||||
.padding(.space1)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
}
|
||||
|
||||
Text("**Note:** In case the device doesn't have a notch, the loading bar will be displayed with a regular layout.")
|
||||
.font(.footnote)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, .space2)
|
||||
}
|
||||
.padding(.space6)
|
||||
.navigationTitle("Notch Example")
|
||||
}
|
||||
.onDisappear {
|
||||
notchGradientLoadingBar.fadeOut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
|
||||
#Preview {
|
||||
// Previews do not provide a key window, therefore button interactions do not display the loading bar.
|
||||
// To view the loading bar in action, run the example application in the simulator.
|
||||
NotchExampleView()
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// SwiftUIExampleView.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import GradientLoadingBar
|
||||
import SwiftUI
|
||||
|
||||
private enum Config {
|
||||
/// The custom gradient colors we use.
|
||||
///
|
||||
/// Source: <https://color.adobe.com/Pink-Flamingo-color-theme-10343714/>
|
||||
static let gradientColors = [
|
||||
#colorLiteral(red: 0.9490196078, green: 0.3215686275, blue: 0.431372549, alpha: 1), #colorLiteral(red: 0.9450980392, green: 0.4784313725, blue: 0.5921568627, alpha: 1), #colorLiteral(red: 0.9529411765, green: 0.737254902, blue: 0.7843137255, alpha: 1), #colorLiteral(red: 0.4274509804, green: 0.8666666667, blue: 0.9490196078, alpha: 1), #colorLiteral(red: 0.7568627451, green: 0.9411764706, blue: 0.9568627451, alpha: 1),
|
||||
].map(Color.init)
|
||||
}
|
||||
|
||||
/// A SwiftUI view demonstrating the usage of the `GradientLoadingBarView`,
|
||||
/// showcasing both default and custom gradient colors.
|
||||
struct SwiftUIExampleView: View {
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: .space6) {
|
||||
VStack(spacing: .space2) {
|
||||
Text("Default Gradient Colors")
|
||||
.font(.callout)
|
||||
|
||||
GradientLoadingBarView()
|
||||
.frame(height: 3)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 1.5))
|
||||
}
|
||||
|
||||
VStack(spacing: .space2) {
|
||||
Text("Custom Gradient Colors")
|
||||
.font(.callout)
|
||||
|
||||
GradientLoadingBarView(
|
||||
gradientColors: Config.gradientColors,
|
||||
)
|
||||
.frame(height: 3)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 1.5))
|
||||
}
|
||||
}
|
||||
.padding(.space6)
|
||||
.navigationTitle("SwiftUI Example")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
|
||||
#Preview {
|
||||
SwiftUIExampleView()
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// UIKitExampleView.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import GradientLoadingBar
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
private enum Config {
|
||||
/// The custom gradient colors we use.
|
||||
///
|
||||
/// Source: <https://color.adobe.com/Pink-Flamingo-color-theme-10343714/>
|
||||
static let gradientColors = [
|
||||
#colorLiteral(red: 0.9490196078, green: 0.3215686275, blue: 0.431372549, alpha: 1), #colorLiteral(red: 0.9450980392, green: 0.4784313725, blue: 0.5921568627, alpha: 1), #colorLiteral(red: 0.9529411765, green: 0.737254902, blue: 0.7843137255, alpha: 1), #colorLiteral(red: 0.4274509804, green: 0.8666666667, blue: 0.9490196078, alpha: 1), #colorLiteral(red: 0.7568627451, green: 0.9411764706, blue: 0.9568627451, alpha: 1),
|
||||
]
|
||||
}
|
||||
|
||||
/// A SwiftUI view that demonstrates the usage of `GradientActivityIndicatorView` from UIKit.
|
||||
struct UIKitExampleView: View {
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
UIKitExampleViewControllerRepresentable()
|
||||
.navigationTitle("UIKit Example")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Supporting Types
|
||||
|
||||
/// A UIViewControllerRepresentable that wraps the `UIKitExampleViewController`.
|
||||
private struct UIKitExampleViewControllerRepresentable: UIViewControllerRepresentable {
|
||||
func makeUIViewController(context _: Context) -> UIViewController {
|
||||
UIKitExampleViewController()
|
||||
}
|
||||
|
||||
func updateUIViewController(_: UIViewController, context _: Context) {}
|
||||
}
|
||||
|
||||
/// A UIViewController that showcases the `GradientActivityIndicatorView`
|
||||
/// with default and custom gradient colors.
|
||||
private final class UIKitExampleViewController: UIViewController {
|
||||
|
||||
// MARK: - Private Properties
|
||||
|
||||
private let contentStackView = UIStackView()
|
||||
|
||||
private let defaultGradientColorsLabel = UILabel()
|
||||
private let defaultGradientActivityIndicatorView = GradientActivityIndicatorView()
|
||||
|
||||
private let customGradientColorsLabel = UILabel()
|
||||
private let customGradientActivityIndicatorView = GradientActivityIndicatorView()
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setUpSubviews()
|
||||
setUpConstraints()
|
||||
}
|
||||
|
||||
// MARK: - Private Methods
|
||||
|
||||
private func setUpSubviews() {
|
||||
contentStackView.axis = .vertical
|
||||
contentStackView.alignment = .fill
|
||||
contentStackView.spacing = .space2
|
||||
contentStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(contentStackView)
|
||||
|
||||
defaultGradientColorsLabel.text = "Default Gradient Colors"
|
||||
defaultGradientColorsLabel.textAlignment = .center
|
||||
defaultGradientColorsLabel.font = .preferredFont(forTextStyle: .callout)
|
||||
contentStackView.addArrangedSubview(defaultGradientColorsLabel)
|
||||
|
||||
contentStackView.addArrangedSubview(defaultGradientActivityIndicatorView)
|
||||
contentStackView.setCustomSpacing(.space6, after: defaultGradientActivityIndicatorView)
|
||||
|
||||
customGradientColorsLabel.text = "Custom Gradient Colors"
|
||||
customGradientColorsLabel.textAlignment = .center
|
||||
customGradientColorsLabel.font = .preferredFont(forTextStyle: .callout)
|
||||
contentStackView.addArrangedSubview(customGradientColorsLabel)
|
||||
|
||||
customGradientActivityIndicatorView.gradientColors = Config.gradientColors
|
||||
contentStackView.addArrangedSubview(customGradientActivityIndicatorView)
|
||||
}
|
||||
|
||||
private func setUpConstraints() {
|
||||
NSLayoutConstraint.activate([
|
||||
contentStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: .space6),
|
||||
contentStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -.space6),
|
||||
contentStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
|
||||
defaultGradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: 3),
|
||||
|
||||
customGradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: 3),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
|
||||
#Preview {
|
||||
UIKitExampleView()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// GradientLoadingBarExampleApp.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct GradientLoadingBarExampleApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// CGFloat+Spacing.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreGraphics
|
||||
|
||||
/// Standard spacing values based on a 4-point grid.
|
||||
///
|
||||
/// These constants provide a shared spacing scale to ensure visual consistency across layouts.
|
||||
/// Values are expressed in points and increase in 4-point increments.
|
||||
///
|
||||
/// Naming follows the pattern `spaceN`, where `N` represents the number of 4-point units (e.g. `space3` = 12 points).
|
||||
///
|
||||
/// ### Usage
|
||||
///
|
||||
/// ```swift
|
||||
/// VStack(spacing: .space4) {
|
||||
/// Text("Title")
|
||||
/// Text("Subtitle")
|
||||
/// }
|
||||
/// ```
|
||||
extension CGFloat {
|
||||
static let space0: CGFloat = 0
|
||||
static let space1: CGFloat = 4
|
||||
static let space2: CGFloat = 8
|
||||
static let space3: CGFloat = 12
|
||||
static let space4: CGFloat = 16
|
||||
static let space5: CGFloat = 20
|
||||
static let space6: CGFloat = 24
|
||||
static let space8: CGFloat = 32
|
||||
static let space10: CGFloat = 40
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// SFSymbol.swift
|
||||
// GradientLoadingBarExample
|
||||
//
|
||||
// Created by Felix Mau on 10.01.26.
|
||||
// Copyright © 2026 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
/// SF Symbols used by the example application.
|
||||
///
|
||||
/// Using an enum avoids hard-coded string literals and improves discoverability, autocompletion and compile-time safety.
|
||||
/// The raw value of each case corresponds to the SF Symbol’s system name.
|
||||
enum SFSymbol: String {
|
||||
case eye
|
||||
case eyeSlash = "eye.slash"
|
||||
case iPhoneGen2 = "iphone.gen2"
|
||||
case iPhoneGen3 = "iphone.gen3"
|
||||
case squareStack = "square.stack"
|
||||
case swift
|
||||
}
|
||||
|
||||
// MARK: - Helper
|
||||
|
||||
extension Image {
|
||||
/// Creates a SwiftUI `Image` from an `SFSymbol`.
|
||||
///
|
||||
/// ### Usage
|
||||
///
|
||||
/// ```swift
|
||||
/// Image(sfSymbol: .house)
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter sfSymbol: The SF Symbol to display.
|
||||
init(sfSymbol: SFSymbol) {
|
||||
self.init(systemName: sfSymbol.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIImage {
|
||||
/// Creates a `UIImage` from an `SFSymbol`.
|
||||
///
|
||||
/// ### Usage
|
||||
///
|
||||
/// ```swift
|
||||
/// let image = UIImage(sfSymbol: .plus)
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter sfSymbol: The SF Symbol to display.
|
||||
///
|
||||
/// - Returns: A system image, or `nil` if the symbol name is invalid or
|
||||
/// unavailable on the current OS version.
|
||||
convenience init?(sfSymbol: SFSymbol) {
|
||||
self.init(systemName: sfSymbol.rawValue)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user