Files
GradientLoadingBar/SwiftUI/GradientLoadingBarView.swift
T

70 lines
2.4 KiB
Swift

//
// GradientLoadingBarView.swift
// GradientLoadingBar
//
// Created by Felix Mau on 08.03.22.
// Copyright © 2022 Felix Mau. All rights reserved.
//
import SwiftUI
@available(iOS 13.0, *)
public struct GradientLoadingBarView: View {
// MARK: - Config
public enum Config {
/// The default color palette for the gradient colors.
public static let gradientColors = UIColor.GradientLoadingBar.gradientColors.map(Color.init)
/// The default duration for the progress animation, measured in seconds.
public static let progressDuration = TimeInterval.GradientLoadingBar.progressDuration
}
// MARK: - Private properties
private let gradientColors: [Color]
private let progressAnimation: Animation
@State
private var offset: CGFloat = 0
// MARK: - Initializer
public init(gradientColors: [Color] = Config.gradientColors,
progressDuration: TimeInterval = Config.progressDuration) {
// E.g. for array of [.red, .yellow, .green]
// we will create [.red, .yellow, .green, .yellow, .red, .yellow, .green]
//
// E.g. for array of [.red, .yellow, .green, .blue]
// we will create [.red, .yellow, .green, .blue, .green, .yellow, .red, .yellow, .green, .blue]
var reversedGradientColors = Array(gradientColors.reversed())
reversedGradientColors.removeFirst()
reversedGradientColors.removeLast()
self.gradientColors = gradientColors + reversedGradientColors + gradientColors
progressAnimation = .linear(duration: progressDuration).repeatForever(autoreverses: false)
}
// MARK: - Render
public var body: some View {
GeometryReader { proxy in
LinearGradient(colors: gradientColors, startPoint: .leading, endPoint: .trailing)
// To fit `gradientColors + reversedGradientColors + gradientColors` in our view,
// we have to apply three times the width of our parent view.
.frame(width: proxy.size.width * 3)
.offset(x: offset, y: 0)
.onAppear {
// We want to animate from left to right.
// Therefore we start with the negative offset, and afterwards animate to an offset of zero.
offset = proxy.size.width * -2
withAnimation(progressAnimation) {
offset = 0
}
}
}
}
}