mirror of
https://github.com/fxm90/GradientLoadingBar.git
synced 2026-06-16 12:24:31 +00:00
♻️ :: Moved logic from view to view-model
This commit is contained in:
+4
@@ -38,6 +38,7 @@
|
||||
4B5A5EBA97A912894C10D040B5A1225D /* Pods-GradientLoadingBar_Tests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B8B5E60915249521CF9DC7208F2D5774 /* Pods-GradientLoadingBar_Tests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
604C51928D4CFDAE15A6CAB6327B68D6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B802EDB707F8CE8EBD66EB815051159F /* Foundation.framework */; };
|
||||
640E8ABC2313DD280008C5A6 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640E8ABB2313DD280008C5A6 /* Constants.swift */; };
|
||||
640E8ABE2313E4540008C5A6 /* GradientActivityIndicatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640E8ABD2313E4540008C5A6 /* GradientActivityIndicatorViewModel.swift */; };
|
||||
681130A53798D8143A2C972C3351D165 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B802EDB707F8CE8EBD66EB815051159F /* Foundation.framework */; };
|
||||
757352462D522BDB0B228DE9880106ED /* Pods-GradientLoadingBar_Tests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E014E4CD6DE59FD4C7C3D12C2BC9474 /* Pods-GradientLoadingBar_Tests-dummy.m */; };
|
||||
7D00DA81B76090CC52ADBEC7E56F8A4B /* GradientLoadingBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D0266A0CC59CB31FD536223C0F4096 /* GradientLoadingBarController.swift */; };
|
||||
@@ -125,6 +126,7 @@
|
||||
5459A35FCB502D3A65BE88C4A1A7C819 /* GradientActivityIndicatorView+AnimateIsHidden.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "GradientActivityIndicatorView+AnimateIsHidden.swift"; sourceTree = "<group>"; };
|
||||
59286ACC8816C332C7919AEBF42BC6EB /* GradientLoadingBar.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = GradientLoadingBar.podspec; sourceTree = "<group>"; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
|
||||
640E8ABB2313DD280008C5A6 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
640E8ABD2313E4540008C5A6 /* GradientActivityIndicatorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientActivityIndicatorViewModel.swift; sourceTree = "<group>"; };
|
||||
670D1598351BCDDA2ACA6F3ECB0434BB /* SwiftFormat.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftFormat.xcconfig; sourceTree = "<group>"; };
|
||||
67873E92210DD4E777C49C6E8AEDC108 /* GradientLoadingBar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GradientLoadingBar.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7471906D53E2B2BEDC58FEDF3DC82244 /* Pods-GradientLoadingBar_Example-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-GradientLoadingBar_Example-dummy.m"; sourceTree = "<group>"; };
|
||||
@@ -302,6 +304,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8AB9BDBFBE2396FB45EEB12E7B9C6067 /* GradientLoadingBarViewModel.swift */,
|
||||
640E8ABD2313E4540008C5A6 /* GradientActivityIndicatorViewModel.swift */,
|
||||
);
|
||||
name = ViewModel;
|
||||
path = GradientLoadingBar/Classes/ViewModel;
|
||||
@@ -625,6 +628,7 @@
|
||||
8BD7971BD44E1BB5E96B9BD7F1047F0F /* GradientActivityIndicatorView+AnimateIsHidden.swift in Sources */,
|
||||
B4876567964EBC1B95C76559240D1AAB /* GradientActivityIndicatorView.swift in Sources */,
|
||||
7F0493B920FABFACCE19457C63AD9719 /* GradientLoadingBar-dummy.m in Sources */,
|
||||
640E8ABE2313E4540008C5A6 /* GradientActivityIndicatorViewModel.swift in Sources */,
|
||||
7D00DA81B76090CC52ADBEC7E56F8A4B /* GradientLoadingBarController.swift in Sources */,
|
||||
3F7EF08A0DB32C7543CFDDB67068D548 /* GradientLoadingBarViewModel.swift in Sources */,
|
||||
640E8ABC2313DD280008C5A6 /* Constants.swift in Sources */,
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// GradientActivityIndicatorViewModel.swift
|
||||
// GradientLoadingBar
|
||||
//
|
||||
// Created by Felix Mau on 08/26/19.
|
||||
// Copyright © 2019 Felix Mau. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import LightweightObservable
|
||||
|
||||
class GradientActivityIndicatorViewModel {
|
||||
// MARK: - Types
|
||||
|
||||
///
|
||||
enum AnimationState: Equatable {
|
||||
case none
|
||||
case animating(duration: TimeInterval)
|
||||
}
|
||||
|
||||
// MARK: - Public properties
|
||||
|
||||
///
|
||||
var animationState: Observable<AnimationState> {
|
||||
return animationStateSubject.asObservable
|
||||
}
|
||||
|
||||
///
|
||||
var infinteGradientColors: Observable<[CGColor]> {
|
||||
return infinteGradientColorsSubject.asObservable
|
||||
}
|
||||
|
||||
///
|
||||
var isHidden = false {
|
||||
didSet {
|
||||
if isHidden {
|
||||
animationStateSubject.value = .none
|
||||
} else {
|
||||
animationStateSubject.value = .animating(duration: progressAnimationDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Colors used for the gradient.
|
||||
var gradientColors = UIColor.GradientLoadingBar.gradientColors {
|
||||
didSet {
|
||||
infinteGradientColorsSubject.value = makeInfiniteGradientColors()
|
||||
}
|
||||
}
|
||||
|
||||
/// Duration for the progress animation.
|
||||
var progressAnimationDuration = TimeInterval.GradientLoadingBar.progressDuration
|
||||
|
||||
// MARK: - Private properties
|
||||
|
||||
private let infinteGradientColorsSubject: Variable<[CGColor]> = Variable([])
|
||||
|
||||
private let animationStateSubject: Variable<AnimationState> = Variable(.none)
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
/// Simulate infinte animation - Therefore we'll reverse the colors and remove the first and last item
|
||||
/// to prevent duplicate values at the "inner edges" destroying the infinite look.
|
||||
private func makeInfiniteGradientColors() -> [CGColor] {
|
||||
let reversedColors = gradientColors
|
||||
.reversed()
|
||||
.dropFirst()
|
||||
.dropLast()
|
||||
|
||||
let infiniteGradientColors = gradientColors + reversedColors + gradientColors
|
||||
return infiniteGradientColors.map { $0.cgColor }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import LightweightObservable
|
||||
|
||||
@IBDesignable
|
||||
open class GradientActivityIndicatorView: UIView {
|
||||
@@ -19,37 +20,32 @@ open class GradientActivityIndicatorView: UIView {
|
||||
|
||||
open override var isHidden: Bool {
|
||||
didSet {
|
||||
if isHidden {
|
||||
stopProgressAnimation()
|
||||
} else {
|
||||
startProgressAnimation()
|
||||
}
|
||||
viewModel.isHidden = isHidden
|
||||
}
|
||||
}
|
||||
|
||||
/// Duration for the progress animation.
|
||||
public var progressAnimationDuration = TimeInterval.GradientLoadingBar.progressDuration
|
||||
public var progressAnimationDuration: TimeInterval {
|
||||
get {
|
||||
return viewModel.progressAnimationDuration
|
||||
}
|
||||
set {
|
||||
viewModel.progressAnimationDuration = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Colors used for the gradient.
|
||||
public var gradientColorList = UIColor.GradientLoadingBar.gradientColorList {
|
||||
didSet {
|
||||
gradientLayer.colors = infinteColorList.map { $0.cgColor }
|
||||
public var gradientColors: [UIColor] {
|
||||
get {
|
||||
return viewModel.gradientColors
|
||||
}
|
||||
set {
|
||||
viewModel.gradientColors = newValue
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private properties
|
||||
|
||||
/// Simulate infinte animation - Therefore we'll reverse the colors and remove the first and last item
|
||||
/// to prevent duplicate values at the "inner edges" destroying the infinite look.
|
||||
private var infinteColorList: [UIColor] {
|
||||
let reversedColorList = gradientColorList
|
||||
.reversed()
|
||||
.dropFirst()
|
||||
.dropLast()
|
||||
|
||||
return gradientColorList + reversedColorList + gradientColorList
|
||||
}
|
||||
|
||||
/// Layer holding the gradient.
|
||||
private var gradientLayer: CAGradientLayer = {
|
||||
let layer = CAGradientLayer()
|
||||
@@ -61,6 +57,12 @@ open class GradientActivityIndicatorView: UIView {
|
||||
return layer
|
||||
}()
|
||||
|
||||
///
|
||||
private let viewModel = GradientActivityIndicatorViewModel()
|
||||
|
||||
/// The dispose bag for the observables.
|
||||
private var disposeBag = DisposeBag()
|
||||
|
||||
// MARK: - Initializers
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
@@ -102,21 +104,35 @@ open class GradientActivityIndicatorView: UIView {
|
||||
// MARK: - Private methods
|
||||
|
||||
private func commonInit() {
|
||||
gradientLayer.colors = infinteColorList.map { $0.cgColor }
|
||||
layer.insertSublayer(gradientLayer, at: 0)
|
||||
layer.masksToBounds = true
|
||||
|
||||
startProgressAnimation()
|
||||
bindViewModelToView()
|
||||
}
|
||||
|
||||
private func startProgressAnimation() {
|
||||
private func bindViewModelToView() {
|
||||
viewModel.infinteGradientColors.subscribeDistinct { [weak self] newInfinteGradientColors, _ in
|
||||
self?.gradientLayer.colors = newInfinteGradientColors
|
||||
}.disposed(by: &disposeBag)
|
||||
|
||||
viewModel.animationState.subscribeDistinct { [weak self] newAnimationState, _ in
|
||||
switch newAnimationState {
|
||||
case .none:
|
||||
self?.stopProgressAnimation()
|
||||
case let .animating(duration):
|
||||
self?.startProgressAnimation(duration: duration)
|
||||
}
|
||||
}.disposed(by: &disposeBag)
|
||||
}
|
||||
|
||||
private func startProgressAnimation(duration: TimeInterval) {
|
||||
let animation = CABasicAnimation(keyPath: "position")
|
||||
|
||||
animation.fromValue = CGPoint(x: -2 * bounds.size.width, y: 0)
|
||||
animation.toValue = CGPoint.zero
|
||||
animation.isRemovedOnCompletion = false
|
||||
animation.repeatCount = Float.infinity
|
||||
animation.duration = progressAnimationDuration
|
||||
animation.duration = duration
|
||||
|
||||
gradientLayer.add(animation, forKey: GradientActivityIndicatorView.progressAnimationKey)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user