diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index c836f11..2bedf65 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -19,13 +19,17 @@ DCA9837627D693BB00D6EA30 /* BasicExample.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DCA9837527D693BB00D6EA30 /* BasicExample.storyboard */; }; DCA9837827D6951C00D6EA30 /* SafeAreaExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA9837727D6951C00D6EA30 /* SafeAreaExampleViewController.swift */; }; DCA9837A27D6958500D6EA30 /* SafeAreaExample.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DCA9837927D6958500D6EA30 /* SafeAreaExample.storyboard */; }; - DCA9838027D69C9300D6EA30 /* AdvancedExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA9837F27D69C9300D6EA30 /* AdvancedExampleViewController.swift */; }; - DCA9838227D69D3F00D6EA30 /* AdvancedExample.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DCA9838127D69D3F00D6EA30 /* AdvancedExample.storyboard */; }; DCA9838727D6A44700D6EA30 /* NavigationBarExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA9838627D6A44700D6EA30 /* NavigationBarExampleViewController.swift */; }; DCA9838927D6A55A00D6EA30 /* NavigationBarExample.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DCA9838827D6A55A00D6EA30 /* NavigationBarExample.storyboard */; }; DCA9838B27D6A74800D6EA30 /* SwiftUIExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA9838A27D6A74800D6EA30 /* SwiftUIExampleView.swift */; }; + F50E4C7E28061655001232D3 /* AdvancedExample.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F50E4C7D28061655001232D3 /* AdvancedExample.storyboard */; }; + F50E4C8028061715001232D3 /* AdvancedExampleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F50E4C7F28061715001232D3 /* AdvancedExampleTableViewController.swift */; }; F560001227EA2032001913A0 /* GradientLoadingBarView+ViewModelTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F560001127EA2032001913A0 /* GradientLoadingBarView+ViewModelTestCase.swift */; }; F57C83C927DA11580025AA11 /* GradientLoadingBarViewTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F57C83C827DA11580025AA11 /* GradientLoadingBarViewTestCase.swift */; }; + F5C7E8882809CDEE00036B8E /* CustomColorsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C7E8872809CDEE00036B8E /* CustomColorsTableViewCell.swift */; }; + F5C7E88A2809CDF600036B8E /* InterfaceBuilderSetupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C7E8892809CDF600036B8E /* InterfaceBuilderSetupTableViewCell.swift */; }; + F5C7E88C2809CDFD00036B8E /* CustomSuperviewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C7E88B2809CDFD00036B8E /* CustomSuperviewTableViewCell.swift */; }; + F5C7E88F2809CF1200036B8E /* BorderedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C7E88E2809CF1200036B8E /* BorderedButton.swift */; }; F5F5B69C27D94B1800D998B5 /* GradientActivityIndicatorView+AnimateIsHiddenTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F5B69727D94B1800D998B5 /* GradientActivityIndicatorView+AnimateIsHiddenTestCase.swift */; }; F5F5B69D27D94B1800D998B5 /* GradientLoadingBarViewModelTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F5B69927D94B1800D998B5 /* GradientLoadingBarViewModelTestCase.swift */; }; F5F5B69E27D94B1800D998B5 /* GradientActivityIndicatorViewModelTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F5B69A27D94B1800D998B5 /* GradientActivityIndicatorViewModelTestCase.swift */; }; @@ -73,13 +77,17 @@ DCA9837527D693BB00D6EA30 /* BasicExample.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = BasicExample.storyboard; sourceTree = ""; }; DCA9837727D6951C00D6EA30 /* SafeAreaExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeAreaExampleViewController.swift; sourceTree = ""; }; DCA9837927D6958500D6EA30 /* SafeAreaExample.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SafeAreaExample.storyboard; sourceTree = ""; }; - DCA9837F27D69C9300D6EA30 /* AdvancedExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedExampleViewController.swift; sourceTree = ""; }; - DCA9838127D69D3F00D6EA30 /* AdvancedExample.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AdvancedExample.storyboard; sourceTree = ""; }; DCA9838627D6A44700D6EA30 /* NavigationBarExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarExampleViewController.swift; sourceTree = ""; }; DCA9838827D6A55A00D6EA30 /* NavigationBarExample.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NavigationBarExample.storyboard; sourceTree = ""; }; DCA9838A27D6A74800D6EA30 /* SwiftUIExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIExampleView.swift; sourceTree = ""; }; + F50E4C7D28061655001232D3 /* AdvancedExample.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AdvancedExample.storyboard; sourceTree = ""; }; + F50E4C7F28061715001232D3 /* AdvancedExampleTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedExampleTableViewController.swift; sourceTree = ""; }; F560001127EA2032001913A0 /* GradientLoadingBarView+ViewModelTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GradientLoadingBarView+ViewModelTestCase.swift"; sourceTree = ""; }; F57C83C827DA11580025AA11 /* GradientLoadingBarViewTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientLoadingBarViewTestCase.swift; sourceTree = ""; }; + F5C7E8872809CDEE00036B8E /* CustomColorsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomColorsTableViewCell.swift; sourceTree = ""; }; + F5C7E8892809CDF600036B8E /* InterfaceBuilderSetupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceBuilderSetupTableViewCell.swift; sourceTree = ""; }; + F5C7E88B2809CDFD00036B8E /* CustomSuperviewTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSuperviewTableViewCell.swift; sourceTree = ""; }; + F5C7E88E2809CF1200036B8E /* BorderedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BorderedButton.swift; sourceTree = ""; }; F5F5B69727D94B1800D998B5 /* GradientActivityIndicatorView+AnimateIsHiddenTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GradientActivityIndicatorView+AnimateIsHiddenTestCase.swift"; sourceTree = ""; }; F5F5B69927D94B1800D998B5 /* GradientLoadingBarViewModelTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientLoadingBarViewModelTestCase.swift; sourceTree = ""; }; F5F5B69A27D94B1800D998B5 /* GradientActivityIndicatorViewModelTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientActivityIndicatorViewModelTestCase.swift; sourceTree = ""; }; @@ -227,8 +235,10 @@ DCA9836E27D6909A00D6EA30 /* AdvancedExample */ = { isa = PBXGroup; children = ( - DCA9838127D69D3F00D6EA30 /* AdvancedExample.storyboard */, - DCA9837F27D69C9300D6EA30 /* AdvancedExampleViewController.swift */, + F5C7E8862809CDE200036B8E /* Cells */, + F5C7E88D2809CF0700036B8E /* Views */, + F50E4C7D28061655001232D3 /* AdvancedExample.storyboard */, + F50E4C7F28061715001232D3 /* AdvancedExampleTableViewController.swift */, ); path = AdvancedExample; sourceTree = ""; @@ -259,6 +269,24 @@ path = NavigationBarExample; sourceTree = ""; }; + F5C7E8862809CDE200036B8E /* Cells */ = { + isa = PBXGroup; + children = ( + F5C7E8872809CDEE00036B8E /* CustomColorsTableViewCell.swift */, + F5C7E8892809CDF600036B8E /* InterfaceBuilderSetupTableViewCell.swift */, + F5C7E88B2809CDFD00036B8E /* CustomSuperviewTableViewCell.swift */, + ); + path = Cells; + sourceTree = ""; + }; + F5C7E88D2809CF0700036B8E /* Views */ = { + isa = PBXGroup; + children = ( + F5C7E88E2809CF1200036B8E /* BorderedButton.swift */, + ); + path = Views; + sourceTree = ""; + }; F5F5B69627D94B1800D998B5 /* Views */ = { isa = PBXGroup; children = ( @@ -426,9 +454,9 @@ buildActionMask = 2147483647; files = ( DCA9834127D68AD600D6EA30 /* Preview Assets.xcassets in Resources */, + F50E4C7E28061655001232D3 /* AdvancedExample.storyboard in Resources */, DCA9837A27D6958500D6EA30 /* SafeAreaExample.storyboard in Resources */, DCA9837627D693BB00D6EA30 /* BasicExample.storyboard in Resources */, - DCA9838227D69D3F00D6EA30 /* AdvancedExample.storyboard in Resources */, DCA9833E27D68AD600D6EA30 /* Assets.xcassets in Resources */, DCA9838927D6A55A00D6EA30 /* NavigationBarExample.storyboard in Resources */, ); @@ -597,8 +625,12 @@ files = ( DCA9837127D6912300D6EA30 /* BasicExampleViewController.swift in Sources */, DCA9833A27D68AD400D6EA30 /* ExampleApp.swift in Sources */, - DCA9838027D69C9300D6EA30 /* AdvancedExampleViewController.swift in Sources */, + F5C7E88F2809CF1200036B8E /* BorderedButton.swift in Sources */, + F5C7E8882809CDEE00036B8E /* CustomColorsTableViewCell.swift in Sources */, DCA9836927D68E3500D6EA30 /* StoryboardView.swift in Sources */, + F5C7E88C2809CDFD00036B8E /* CustomSuperviewTableViewCell.swift in Sources */, + F5C7E88A2809CDF600036B8E /* InterfaceBuilderSetupTableViewCell.swift in Sources */, + F50E4C8028061715001232D3 /* AdvancedExampleTableViewController.swift in Sources */, DCA9836C27D6905000D6EA30 /* EntryPointView.swift in Sources */, DCA9837827D6951C00D6EA30 /* SafeAreaExampleViewController.swift in Sources */, DCA9838727D6A44700D6EA30 /* NavigationBarExampleViewController.swift in Sources */, diff --git a/Example/Example/Scenes/AdvancedExample/AdvancedExample.storyboard b/Example/Example/Scenes/AdvancedExample/AdvancedExample.storyboard index 8c834c2..9ae3a94 100644 --- a/Example/Example/Scenes/AdvancedExample/AdvancedExample.storyboard +++ b/Example/Example/Scenes/AdvancedExample/AdvancedExample.storyboard @@ -1,97 +1,164 @@ - + - - + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + diff --git a/Example/Example/Scenes/AdvancedExample/AdvancedExampleTableViewController.swift b/Example/Example/Scenes/AdvancedExample/AdvancedExampleTableViewController.swift new file mode 100644 index 0000000..e4448ba --- /dev/null +++ b/Example/Example/Scenes/AdvancedExample/AdvancedExampleTableViewController.swift @@ -0,0 +1,138 @@ +// +// AdvancedExampleTableViewController.swift +// Example +// +// Created by Felix Mau on 12.04.22. +// Copyright © 2022 Felix Mau. All rights reserved. +// + +import UIKit +import SwiftUI +import GradientLoadingBar + +final class AdvancedExampleTableViewController: UITableViewController { + // MARK: - Config + + 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), + ] + + /// + static let firstSectionHeaderHeight: CGFloat = 48 + + /// + static let defaultSectionHeaderHeight: CGFloat = 32 + } + + // MARK: - Types + + private enum Section: CaseIterable { + case customColors + case interfaceBuilderSetup + case customSuperview + + var cellIdentifier: String { + switch self { + case .customColors: + return CustomColorsTableViewCell.reuseIdentifier + + case .interfaceBuilderSetup: + return InterfaceBuilderSetupTableViewCell.reuseIdentifier + + case .customSuperview: + return CustomSuperviewTableViewCell.reuseIdentifier + } + } + + var sectionTitle: String { + switch self { + case .customColors: + return "Custom Colors" + + case .interfaceBuilderSetup: + return "Interface Builder Setup" + + case .customSuperview: + return "Custom Superview" + } + } + + var sectionHeaderHeight: CGFloat { + switch self { + case .customColors: + return Config.firstSectionHeaderHeight + + case .interfaceBuilderSetup, .customSuperview: + return Config.defaultSectionHeaderHeight + } + } + } + + // MARK: - Private properties + + private let gradientLoadingBar = GradientLoadingBar() + + // MARK: - Public methods + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemGroupedBackground + + gradientLoadingBar.gradientColors = Config.gradientColors + } + + // MARK: - Table view data source + + override func numberOfSections(in _: UITableView) -> Int { + Section.allCases.count + } + + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + 1 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let section = Section.allCases[indexPath.section] + switch section { + case .customColors: + guard let cell = tableView.dequeueReusableCell(withIdentifier: section.cellIdentifier, for: indexPath) as? CustomColorsTableViewCell else { + fatalError("⚠️ – Invalid table view setup. Expected to have `CustomColorsTableViewCell` at this point!") + } + + cell.tapHandler = { [weak self] in + if self?.gradientLoadingBar.isHidden == true { + self?.gradientLoadingBar.fadeIn() + } else { + self?.gradientLoadingBar.fadeOut() + } + } + + return cell + + case .interfaceBuilderSetup, .customSuperview: + return tableView.dequeueReusableCell(withIdentifier: section.cellIdentifier, for: indexPath) + } + } + + override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? { + Section.allCases[section].sectionTitle + } + + override func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + Section.allCases[section].sectionHeaderHeight + } +} + +// MARK: - Helper + +struct AdvancedExampleView: View { + var body: some View { + StoryboardView(name: "AdvancedExample") + .navigationTitle("🚀 Advanced Example") + .edgesIgnoringSafeArea(.bottom) + } +} diff --git a/Example/Example/Scenes/AdvancedExample/AdvancedExampleViewController.swift b/Example/Example/Scenes/AdvancedExample/AdvancedExampleViewController.swift deleted file mode 100644 index 1b58df6..0000000 --- a/Example/Example/Scenes/AdvancedExample/AdvancedExampleViewController.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// AdvancedExampleViewController.swift -// Example -// -// Created by Felix Mau on 07.03.22. -// Copyright © 2022 Felix Mau. All rights reserved. -// - -import UIKit -import SwiftUI -import GradientLoadingBar - -final class AdvancedExampleViewController: UIViewController { - // MARK: - Config - - private enum Config { - /// The programatically applied height of the `GradientActivityIndicatorView`. - static let height: CGFloat = 3 - - /// 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), - ] - - static let smallStackViewSpacing: CGFloat = 8 - } - - // MARK: - Outlets - - @IBOutlet private var stackView: UIStackView! - - @IBOutlet private var customColorsButton: UIButton! - - @IBOutlet private var gradientActivityIndicator: GradientActivityIndicatorView! - @IBOutlet private var interfaceBuilderSetupButton: UIButton! - - @IBOutlet private var customSuperviewButton: BorderedButton! - - // MARK: - Private properties - - // swiftlint:disable:next identifier_name - private let customSuperviewGradientActivityIndicatorView = GradientActivityIndicatorView() - private let customColorsGradientLoadingBar = GradientLoadingBar() - - // MARK: - Public methods - - override func viewDidLoad() { - super.viewDidLoad() - - setupStackView() - setupCustomColorsGradientLoadingBar() - setupCustomSuperviewGradientActivityIndicatorView() - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - // Reset any possible visible loading bar. - customColorsGradientLoadingBar.fadeOut() - } - - // MARK: - Private methods - - private func setupStackView() { - stackView.setCustomSpacing(Config.smallStackViewSpacing, after: gradientActivityIndicator) - } - - private func setupCustomColorsGradientLoadingBar() { - customColorsGradientLoadingBar.gradientColors = Config.gradientColors - } - - private func setupCustomSuperviewGradientActivityIndicatorView() { - customSuperviewGradientActivityIndicatorView.isHidden = true - customSuperviewGradientActivityIndicatorView.alpha = 0 - - customSuperviewGradientActivityIndicatorView.translatesAutoresizingMaskIntoConstraints = false - customSuperviewButton.addSubview(customSuperviewGradientActivityIndicatorView) - - NSLayoutConstraint.activate([ - customSuperviewGradientActivityIndicatorView.leadingAnchor.constraint(equalTo: customSuperviewButton.leadingAnchor), - customSuperviewGradientActivityIndicatorView.trailingAnchor.constraint(equalTo: customSuperviewButton.trailingAnchor), - - customSuperviewGradientActivityIndicatorView.topAnchor.constraint(equalTo: customSuperviewButton.topAnchor), - customSuperviewGradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: Config.height), - ]) - } - - @IBAction private func toggleCustomColorsButtonTouchUpInside(_: Any) { - if customColorsGradientLoadingBar.isHidden { - customColorsGradientLoadingBar.fadeIn() - } else { - customColorsGradientLoadingBar.fadeOut() - } - } - - @IBAction private func interfaceBuilderSetupButtonTouchUpInside(_: Any) { - // We explicitly "only" reduce the alpha here, as calling `fadeIn()` / `fadeOut()` would update the `isHidden` - // flag accordingly. This would then lead to a height-update of the parent stack view. - UIView.animate(withDuration: 1.0) { - if self.gradientActivityIndicator.alpha > 0 { - self.gradientActivityIndicator.alpha = 0 - } else { - self.gradientActivityIndicator.alpha = 1 - } - } - } - - @IBAction private func customSuperviewButtonTouchUpInside(_: Any) { - if customSuperviewGradientActivityIndicatorView.isHidden { - customSuperviewGradientActivityIndicatorView.fadeIn() - } else { - customSuperviewGradientActivityIndicatorView.fadeOut() - } - } -} - -// MARK: - Subviews - -@IBDesignable -final class BorderedButton: UIButton { - private enum Config { - static let borderColor = #colorLiteral(red: 0.2862745098, green: 0.5647058824, blue: 0.8862745098, alpha: 1) - static let borderWidth: CGFloat = 1 - static let cornerRadius: CGFloat = 4 - } - - override init(frame: CGRect) { - super.init(frame: frame) - - commonInit() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - commonInit() - } - - private func commonInit() { - backgroundColor = .clear - tintColor = Config.borderColor - - layer.borderColor = Config.borderColor.cgColor - layer.borderWidth = Config.borderWidth - layer.cornerRadius = Config.cornerRadius - layer.masksToBounds = true - } -} - -// MARK: - Helpers - -struct AdvancedExampleView: View { - var body: some View { - StoryboardView(name: "AdvancedExample") - .navigationTitle("🚀 Advanced Example") - } -} diff --git a/Example/Example/Scenes/AdvancedExample/Cells/CustomColorsTableViewCell.swift b/Example/Example/Scenes/AdvancedExample/Cells/CustomColorsTableViewCell.swift new file mode 100644 index 0000000..7a6880a --- /dev/null +++ b/Example/Example/Scenes/AdvancedExample/Cells/CustomColorsTableViewCell.swift @@ -0,0 +1,23 @@ +// +// CustomColorsTableViewCell.swift +// Example +// +// Created by Felix Mau on 15.04.22. +// Copyright © 2022 Felix Mau. All rights reserved. +// + +import UIKit + +final class CustomColorsTableViewCell: UITableViewCell { + // MARK: - Public properties + + static let reuseIdentifier = "CustomColorsTableViewCell" + + var tapHandler: (() -> Void)? + + // MARK: - Private methods + + @IBAction private func customColorsButtonTouchUpInside(_: Any) { + tapHandler?() + } +} diff --git a/Example/Example/Scenes/AdvancedExample/Cells/CustomSuperviewTableViewCell.swift b/Example/Example/Scenes/AdvancedExample/Cells/CustomSuperviewTableViewCell.swift new file mode 100644 index 0000000..c2333f6 --- /dev/null +++ b/Example/Example/Scenes/AdvancedExample/Cells/CustomSuperviewTableViewCell.swift @@ -0,0 +1,61 @@ +// +// CustomSuperviewTableViewCell.swift +// Example +// +// Created by Felix Mau on 15.04.22. +// Copyright © 2022 Felix Mau. All rights reserved. +// + +import UIKit +import GradientLoadingBar + +final class CustomSuperviewTableViewCell: UITableViewCell { + // MARK: - Config + + private enum Config { + static let height: CGFloat = 3 + } + + // MARK: - Outlets + + @IBOutlet private var toggleButton: UIButton! + + // MARK: - Public properties + + static let reuseIdentifier = "CustomSuperviewViewCell" + + // MARK: - Private properties + + private let gradientActivityIndicatorView = GradientActivityIndicatorView() + + // MARK: - Public methods + + override func awakeFromNib() { + super.awakeFromNib() + + setupGradientActivityIndicatorView() + } + + // MARK: - Private methods + + private func setupGradientActivityIndicatorView() { + gradientActivityIndicatorView.translatesAutoresizingMaskIntoConstraints = false + toggleButton.addSubview(gradientActivityIndicatorView) + + NSLayoutConstraint.activate([ + gradientActivityIndicatorView.leadingAnchor.constraint(equalTo: toggleButton.leadingAnchor), + gradientActivityIndicatorView.trailingAnchor.constraint(equalTo: toggleButton.trailingAnchor), + + gradientActivityIndicatorView.bottomAnchor.constraint(equalTo: toggleButton.bottomAnchor), + gradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: Config.height), + ]) + } + + @IBAction private func toggleButtonTouchUpInside(_: Any) { + if gradientActivityIndicatorView.isHidden { + gradientActivityIndicatorView.fadeIn() + } else { + gradientActivityIndicatorView.fadeOut() + } + } +} diff --git a/Example/Example/Scenes/AdvancedExample/Cells/InterfaceBuilderSetupTableViewCell.swift b/Example/Example/Scenes/AdvancedExample/Cells/InterfaceBuilderSetupTableViewCell.swift new file mode 100644 index 0000000..ae4f5f0 --- /dev/null +++ b/Example/Example/Scenes/AdvancedExample/Cells/InterfaceBuilderSetupTableViewCell.swift @@ -0,0 +1,40 @@ +// +// InterfaceBuilderSetupTableViewCell.swift +// Example +// +// Created by Felix Mau on 15.04.22. +// Copyright © 2022 Felix Mau. All rights reserved. +// + +import UIKit +import GradientLoadingBar + +final class InterfaceBuilderSetupTableViewCell: UITableViewCell { + // MARK: - Config + + private enum Config { + static let animationDuration: TimeInterval = 0.5 + } + + // MARK: - Outlets + + @IBOutlet private var gradientActivityIndicator: GradientActivityIndicatorView! + + // MARK: - Public properties + + static let reuseIdentifier = "InterfaceBuilderSetupTableViewCell" + + // MARK: - Private methods + + @IBAction private func toggleIBSetupButtonTouchUpInside(_: Any) { + // We explicitly "only" reduce the alpha here, as calling `fadeIn()` / `fadeOut()` would update the `isHidden` + // flag accordingly. This would then lead to a height-update of the parent stack view. + UIView.animate(withDuration: Config.animationDuration) { + if self.gradientActivityIndicator.alpha > 0 { + self.gradientActivityIndicator.alpha = 0 + } else { + self.gradientActivityIndicator.alpha = 1 + } + } + } +} diff --git a/Example/Example/Scenes/AdvancedExample/Views/BorderedButton.swift b/Example/Example/Scenes/AdvancedExample/Views/BorderedButton.swift new file mode 100644 index 0000000..31a180f --- /dev/null +++ b/Example/Example/Scenes/AdvancedExample/Views/BorderedButton.swift @@ -0,0 +1,46 @@ +// +// BorderedButton.swift +// Example +// +// Created by Felix Mau on 15.04.22. +// Copyright © 2022 Felix Mau. All rights reserved. +// + +import UIKit + +@IBDesignable +final class BorderedButton: UIButton { + // MARK: - Config + + private enum Config { + static let borderColor = #colorLiteral(red: 0.2862745098, green: 0.5647058824, blue: 0.8862745098, alpha: 1) + static let borderWidth: CGFloat = 1 + static let cornerRadius: CGFloat = 4 + } + + // MARK: - Initializer + + override init(frame: CGRect) { + super.init(frame: frame) + + commonInit() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + commonInit() + } + + // MARK: - Private methods + + private func commonInit() { + backgroundColor = .clear + tintColor = Config.borderColor + + layer.borderColor = Config.borderColor.cgColor + layer.borderWidth = Config.borderWidth + layer.cornerRadius = Config.cornerRadius + layer.masksToBounds = true + } +} diff --git a/Example/Example/Scenes/BasicExample/BasicExample.storyboard b/Example/Example/Scenes/BasicExample/BasicExample.storyboard index a0ecff8..857b4b5 100644 --- a/Example/Example/Scenes/BasicExample/BasicExample.storyboard +++ b/Example/Example/Scenes/BasicExample/BasicExample.storyboard @@ -1,8 +1,8 @@ - + - + @@ -16,7 +16,7 @@ - + - + + - diff --git a/Example/Example/Scenes/SwiftUIExample/SwiftUIExampleView.swift b/Example/Example/Scenes/SwiftUIExample/SwiftUIExampleView.swift index 03f13c9..a91709f 100644 --- a/Example/Example/Scenes/SwiftUIExample/SwiftUIExampleView.swift +++ b/Example/Example/Scenes/SwiftUIExample/SwiftUIExampleView.swift @@ -14,17 +14,15 @@ struct SwiftUIExampleView: View { var body: some View { List { - // We need to apply a `Spacer()` as header to have a little space between the sections - // and the navigation bar. - Section(header: Spacer()) { + Section(header: Text("Default example")) { DefaultExampleView() } - Section { + Section(header: Text("Custom colors")) { CustomColorsExampleView() } - Section { + Section(header: Text("Custom animation duration")) { CustomProgressDurationExampleView() } } @@ -34,29 +32,14 @@ struct SwiftUIExampleView: View { // MARK: - Subviews -private struct TitleSubtitleView: View { - let title: String - let subtitle: String - - var body: some View { - VStack(alignment: .leading, spacing: 8) { - Text(title) - .font(.headline) - Text(subtitle) - .font(.subheadline) - } - .frame(maxWidth: .infinity, alignment: .leading) - } -} - private struct DefaultExampleView: View { @State - private var isVisible = false + private var isVisible = true var body: some View { VStack(spacing: 16) { - TitleSubtitleView(title: "Default example", - subtitle: "Example using the default configuration.") + Text("Example using the default configuration.") + .frame(maxWidth: .infinity, alignment: .leading) GradientLoadingBarView() .frame(maxWidth: .infinity, maxHeight: 3) @@ -94,12 +77,12 @@ private struct CustomColorsExampleView: View { } @State - private var isVisible = false + private var isVisible = true var body: some View { VStack(spacing: 16) { - TitleSubtitleView(title: "Custom colors", - subtitle: "Example showing how to provide custom gradient colors.") + Text("Example showing how to provide custom gradient colors.") + .frame(maxWidth: .infinity, alignment: .leading) GradientLoadingBarView(gradientColors: Config.gradientColors) .frame(maxWidth: .infinity, maxHeight: 3) @@ -134,12 +117,12 @@ private struct CustomProgressDurationExampleView: View { } @State - private var isVisible = false + private var isVisible = true var body: some View { VStack(spacing: 16) { - TitleSubtitleView(title: "Custom animation duration", - subtitle: "Example showing how to provide a custom progress animation duration.") + Text("Example showing how to provide a custom progress animation duration.") + .frame(maxWidth: .infinity, alignment: .leading) GradientLoadingBarView(progressDuration: Config.progressDuration) .frame(maxWidth: .infinity, maxHeight: 3)