Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64128d4703 | |||
| 26cf461a5d | |||
| 6d88f8afa0 | |||
| 299f96ca60 | |||
| 71c237eec6 | |||
| 53a3c25f91 | |||
| 56f020ced6 | |||
| 6000d1de0f |
@@ -1,236 +0,0 @@
|
||||
//
|
||||
// M13HUDController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by Brandon McQuilkin on 10/8/15.
|
||||
// Copyright © 2015 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible positions the status title and message can be in.
|
||||
|
||||
- BelowProgress: The text will be below the progress view.
|
||||
- AboveProgress: The text will be above the progress view.
|
||||
- LeadingProgress: The text will lead the progress view.
|
||||
- TrailingProgress: The text will trail the progress view.
|
||||
*/
|
||||
public enum M13HUDStatusTextPosition: Int, RawRepresentable {
|
||||
/// The text will be below the progress view.
|
||||
case BelowProgress
|
||||
/// The text will be above the progress view.
|
||||
case AboveProgress
|
||||
/// The text will lead the progress view.
|
||||
case LeadingProgress
|
||||
/// The text will trail the progress view.
|
||||
case TrailingProgress
|
||||
}
|
||||
|
||||
/**
|
||||
The pre-defined background styles for the HUD. Pass one of these values on initalization to have the background view set up for you.
|
||||
|
||||
- None: Do not add any content to the `backgroundView`.
|
||||
- SolidColor: Set up the `backgroundView` with a solid color background.
|
||||
- LightVisualEffectView: Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with `UIBlurEffectStyleLight` as an option.
|
||||
- ExtraLightVisualEffectView: Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with `UIBlurEffectStyleExtraLight` as an option.
|
||||
- DarkVisualEffectView: Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with `UIBlurEffectStyleDark` as an option.
|
||||
- LightVibrantVisualEffectView: Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with a `UIVibrancyEffect` with `UIBlurEffectStyleLight` as an option.
|
||||
- ExtraLightVibrantVisualEffectView: Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with a `UIVibrancyEffect` with `UIBlurEffectStyleExtraLight` as an option.
|
||||
- DarkVibrantVisualEffectView: Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with a `UIVibrancyEffect` with `UIBlurEffectStyleDark` as an option.
|
||||
*/
|
||||
public enum M13HUDBackgroundStyle: Int, RawRepresentable {
|
||||
/// Do not add any content to the `backgroundView`.
|
||||
case None
|
||||
/// Set up the `backgroundView` with a solid color background.
|
||||
case SolidColor
|
||||
/// Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with `UIBlurEffectStyleLight` as an option.
|
||||
case LightVisualEffectView
|
||||
/// Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with `UIBlurEffectStyleExtraLight` as an option.
|
||||
case ExtraLightVisualEffectView
|
||||
/// Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with `UIBlurEffectStyleDark` as an option.
|
||||
case DarkVisualEffectView
|
||||
/// Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with a `UIVibrancyEffect` with `UIBlurEffectStyleLight` as an option.
|
||||
case LightVibrantVisualEffectView
|
||||
/// Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with a `UIVibrancyEffect` with `UIBlurEffectStyleExtraLight` as an option.
|
||||
case ExtraLightVibrantVisualEffectView
|
||||
/// Set up the `backgroundView` with a `UIVisualEffectView` subview initalized with a `UIVibrancyEffect` with `UIBlurEffectStyleDark` as an option.
|
||||
case DarkVibrantVisualEffectView
|
||||
}
|
||||
|
||||
/**
|
||||
The possible overlay styles of the HUD.
|
||||
|
||||
- FullScreen: The HUD extends over the entire screen.
|
||||
- Rect: The HUD will be a rectangle.
|
||||
- SquareRect: The HUD will be a square.
|
||||
- RoundedRect: The HUD will be a rectangle with rounded corners.
|
||||
- RoundedSquareRect: The HUD will be a square with rounded corners.
|
||||
*/
|
||||
public enum M13HUDOverlayStyle: Int, RawRepresentable {
|
||||
/// The HUD extends over the entire screen.
|
||||
case FullScreen
|
||||
/// The HUD will be a rectangle.
|
||||
case Rect
|
||||
/// The HUD will be a square.
|
||||
case SquareRect
|
||||
/// The HUD will be a rectangle with rounded corners.
|
||||
case RoundedRect
|
||||
/// The HUD will be a square with rounded corners.
|
||||
case RoundedSquareRect
|
||||
}
|
||||
|
||||
/**
|
||||
A customizable view controller that presents an HUD. Works similarly to `UIAlertController`.
|
||||
*/
|
||||
public class M13HUDController: UIViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Appearance
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The position of the title text relative to the progress view.
|
||||
*/
|
||||
public var titlePosition: M13HUDStatusTextPosition = M13HUDStatusTextPosition.AboveProgress
|
||||
|
||||
/**
|
||||
The position of the message text relative to the progress view.
|
||||
*/
|
||||
public var messagePosition: M13HUDStatusTextPosition = M13HUDStatusTextPosition.BelowProgress
|
||||
|
||||
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The message to the user.
|
||||
*/
|
||||
public var message: String?
|
||||
|
||||
/**
|
||||
The view that contains the background view and the content view.
|
||||
*/
|
||||
public let containerView: UIView = UIView()
|
||||
|
||||
/**
|
||||
The view that is the background view. Add any background content to this view.
|
||||
*/
|
||||
public let backgroundView: UIView = UIView()
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
convenience init(backgroundStyle: M13HUDBackgroundStyle) {
|
||||
|
||||
self.init(overlayStyle: M13HUDOverlayStyle.RoundedSquareRect, backgroundStyle: backgroundStyle)
|
||||
}
|
||||
|
||||
convenience init(overlayStyle: M13HUDOverlayStyle) {
|
||||
|
||||
self.init(overlayStyle: overlayStyle, backgroundStyle: M13HUDBackgroundStyle.LightVisualEffectView)
|
||||
}
|
||||
|
||||
convenience init(overlayStyle: M13HUDOverlayStyle, backgroundStyle: M13HUDBackgroundStyle) {
|
||||
|
||||
self.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
|
||||
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
private func sharedSetup() {
|
||||
// Present over a full screen, as this has the posibility of being semi-transparent.
|
||||
modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
|
||||
|
||||
// Add the necessary views
|
||||
view.addSubview(containerView)
|
||||
containerView.addSubview(backgroundView)
|
||||
|
||||
var constraints: [NSLayoutConstraint] = NSLayoutConstraint.constraintsWithVisualFormat("H:|[backgroundView]|", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: ["backgroundView": backgroundView])
|
||||
constraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|[backgroundView]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["backgroundView": backgroundView])
|
||||
NSLayoutConstraint.activateConstraints(constraints)
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization Presets
|
||||
//-------------------------------
|
||||
|
||||
private func setupPresetBackground(backgroundStyle: M13HUDBackgroundStyle) {
|
||||
switch(backgroundStyle) {
|
||||
case .SolidColor:
|
||||
backgroundView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3)
|
||||
break
|
||||
case .LightVisualEffectView:
|
||||
setupBackgroundViewWithVisualEffectView(UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light)))
|
||||
break
|
||||
case .ExtraLightVisualEffectView:
|
||||
setupBackgroundViewWithVisualEffectView(UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.ExtraLight)))
|
||||
break
|
||||
case .DarkVisualEffectView:
|
||||
setupBackgroundViewWithVisualEffectView(UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Dark)))
|
||||
break
|
||||
case .LightVibrantVisualEffectView:
|
||||
setupBackgroundViewWithVisualEffectView(UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: UIBlurEffect(style: UIBlurEffectStyle.Light))))
|
||||
break
|
||||
case .ExtraLightVibrantVisualEffectView:
|
||||
setupBackgroundViewWithVisualEffectView(UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: UIBlurEffect(style: UIBlurEffectStyle.ExtraLight))))
|
||||
break
|
||||
case .DarkVibrantVisualEffectView:
|
||||
setupBackgroundViewWithVisualEffectView(UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: UIBlurEffect(style: UIBlurEffectStyle.Dark))))
|
||||
break
|
||||
case .None:
|
||||
// Do nothing
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func setupBackgroundViewWithVisualEffectView(view: UIVisualEffectView) {
|
||||
backgroundView.addSubview(view)
|
||||
var constraints: [NSLayoutConstraint] = NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: ["view": view])
|
||||
constraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["view": view])
|
||||
NSLayoutConstraint.activateConstraints(constraints)
|
||||
}
|
||||
|
||||
private func setupConstraintsForOverlayStyle(style: M13HUDOverlayStyle) {
|
||||
switch(style) {
|
||||
case .FullScreen:
|
||||
|
||||
break
|
||||
case .Rect:
|
||||
|
||||
break
|
||||
case .SquareRect:
|
||||
|
||||
break
|
||||
case .RoundedRect:
|
||||
|
||||
break
|
||||
case .RoundedSquareRect:
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Other
|
||||
//-------------------------------
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
//
|
||||
// M13BorderedProgressBar.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by Brandon McQuilkin on 9/13/15.
|
||||
// Copyright © 2015 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
A wrapper around M13ProgressBar that adds a border around the bar.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13BorderedProgressBar: M13ProgressView {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Appearance
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The corner radius of the progress bar.
|
||||
*/
|
||||
@IBInspectable public var cornerRadius: CGFloat = CGFloat.max {
|
||||
didSet {
|
||||
progressBar.cornerRadius = cornerRadius
|
||||
setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The width of the border around the progress bar.
|
||||
*/
|
||||
@IBInspectable public var borderWidth: CGFloat = 1.0 {
|
||||
didSet {
|
||||
borderView.layer.borderWidth = borderWidth
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The spacing between the border and the progress bar.
|
||||
*/
|
||||
@IBInspectable public var borderPadding: CGFloat = 1.0
|
||||
|
||||
override public var secondaryColor: UIColor {
|
||||
didSet {
|
||||
progressBar.secondaryColor = secondaryColor
|
||||
}
|
||||
}
|
||||
|
||||
override public var successColor: UIColor {
|
||||
didSet {
|
||||
progressBar.successColor = successColor
|
||||
if state == M13ProgressViewState.Success {
|
||||
borderView.layer.borderColor = successColor.CGColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public var failureColor: UIColor {
|
||||
didSet {
|
||||
progressBar.failureColor = failureColor
|
||||
if state == M13ProgressViewState.Failure {
|
||||
borderView.layer.borderColor = failureColor.CGColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The progress bar that displays the progress.
|
||||
*/
|
||||
public var progressBar: M13ProgressBar = M13ProgressBar() {
|
||||
willSet(newValue) {
|
||||
// Remove the current progress bar from the view.
|
||||
progressBar.removeFromSuperview()
|
||||
}
|
||||
didSet(oldValue) {
|
||||
// Set the current parameters
|
||||
progressBar.cornerRadius = cornerRadius
|
||||
progressBar.secondaryColor = secondaryColor
|
||||
progressBar.successColor = successColor
|
||||
progressBar.failureColor = failureColor
|
||||
progressBar.progressDirection = progressDirection
|
||||
progressBar.indeterminate = indeterminate
|
||||
// Add the new progress bar to the view.
|
||||
addSubview(progressBar)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The view that displays the border layer.
|
||||
*/
|
||||
private var borderView: UIView = UIView()
|
||||
|
||||
/**
|
||||
The direction the progress bar travels in as the progress nears completion.
|
||||
*/
|
||||
@IBInspectable public var progressDirection: M13ProgressBarProgressDirection = M13ProgressBarProgressDirection.LeadingToTrailing {
|
||||
didSet {
|
||||
progressBar.progressDirection = progressDirection
|
||||
}
|
||||
}
|
||||
|
||||
override public var indeterminate: Bool {
|
||||
didSet {
|
||||
progressBar.indeterminate = indeterminate
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("borderWidth") {
|
||||
borderWidth = CGFloat(aDecoder.decodeDoubleForKey("borderWidth"))
|
||||
}
|
||||
if aDecoder.containsValueForKey("borderPadding") {
|
||||
borderWidth = CGFloat(aDecoder.decodeDoubleForKey("borderPadding"))
|
||||
}
|
||||
if aDecoder.containsValueForKey("progressBar") {
|
||||
progressBar = aDecoder.decodeObjectOfClass(M13ProgressBar.self, forKey: "progressBar")!
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
private func sharedSetup() {
|
||||
// Set the defaults.
|
||||
//self.clipsToBounds = true
|
||||
|
||||
// Set border
|
||||
borderView.clipsToBounds = true
|
||||
borderView.layer.borderColor = tintColor.CGColor
|
||||
borderView.layer.borderWidth = borderWidth
|
||||
borderView.backgroundColor = UIColor.clearColor()
|
||||
|
||||
// Set background
|
||||
secondaryColor = UIColor.clearColor()
|
||||
|
||||
// Add views
|
||||
addSubview(progressBar)
|
||||
addSubview(borderView)
|
||||
|
||||
// Set the progress and indeterminate animations.
|
||||
weak var weakSelf: M13BorderedProgressBar? = self;
|
||||
progressUpdate = {() -> Void in
|
||||
if let weakSelf = weakSelf {
|
||||
weakSelf.progressBar.setProgress(weakSelf.progress, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
indeterminateUpdate = {(frameDuration: CFTimeInterval) -> Void in
|
||||
weakSelf?.progressBar.indeterminateUpdate?(frameDuration: frameDuration)
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeDouble(Double(borderWidth), forKey: "borderWidth")
|
||||
aCoder.encodeDouble(Double(borderPadding), forKey: "borderPadding")
|
||||
aCoder.encodeObject(progressBar, forKey: "progressBar")
|
||||
}
|
||||
|
||||
public override func prepareForInterfaceBuilder() {
|
||||
sharedSetup()
|
||||
super.prepareForInterfaceBuilder()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func intrinsicContentSize() -> CGSize {
|
||||
return CGSizeMake((borderWidth * 2) + (borderPadding * 2), (borderWidth * 2) + (borderPadding * 2))
|
||||
}
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
// Update the corner radius
|
||||
var appropiateCornerRadius: CGFloat = frame.size.width < frame.size.height ? frame.size.width / 2.0 : frame.size.height / 2.0
|
||||
appropiateCornerRadius = appropiateCornerRadius > cornerRadius ? cornerRadius : appropiateCornerRadius
|
||||
borderView.layer.cornerRadius = appropiateCornerRadius
|
||||
// Layout
|
||||
borderView.frame = CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)
|
||||
progressBar.frame = CGRectMake(borderWidth + borderPadding, borderWidth + borderPadding, frame.size.width - (2 * (borderWidth + borderPadding)), frame.size.height - (2 * (borderWidth + borderPadding)))
|
||||
// Update progress
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
public override func setState(state: M13ProgressViewState, animated: Bool) {
|
||||
super.setState(state, animated: animated)
|
||||
|
||||
if !animated {
|
||||
switch state {
|
||||
case .Normal:
|
||||
borderView.layer.borderColor = tintColor.CGColor
|
||||
progressBar.setState(state, animated: false)
|
||||
break
|
||||
case .Success:
|
||||
borderView.layer.borderColor = successColor.CGColor
|
||||
progressBar.setState(state, animated: false)
|
||||
break
|
||||
case .Failure:
|
||||
borderView.layer.borderColor = failureColor.CGColor
|
||||
progressBar.setState(state, animated: false)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
let colorAnimation: CABasicAnimation = CABasicAnimation(keyPath: "borderColor")
|
||||
colorAnimation.fromValue = borderView.layer.borderColor!
|
||||
colorAnimation.fillMode = kCAFillModeForwards
|
||||
colorAnimation.removedOnCompletion = false
|
||||
colorAnimation.duration = animationDuration
|
||||
|
||||
var toColor: UIColor = tintColor
|
||||
switch state {
|
||||
case .Normal:
|
||||
toColor = tintColor
|
||||
break
|
||||
case .Success:
|
||||
toColor = successColor
|
||||
break
|
||||
case .Failure:
|
||||
toColor = failureColor
|
||||
break
|
||||
}
|
||||
|
||||
colorAnimation.toValue = toColor.CGColor
|
||||
borderView.layer.addAnimation(colorAnimation, forKey: "borderColor")
|
||||
progressBar.setState(state, animated: true)
|
||||
borderView.layer.borderColor = toColor.CGColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Other
|
||||
//-------------------------------
|
||||
|
||||
public override func tintColorDidChange() {
|
||||
super.tintColorDidChange()
|
||||
borderView.layer.borderColor = tintColor.CGColor
|
||||
}
|
||||
}
|
||||
@@ -1,376 +0,0 @@
|
||||
//
|
||||
// M13ProgressBar.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible directions a progress bar can travel in.
|
||||
|
||||
- LeadingToTrailing: The progress bar will travel from leading to trailing as the progress nears completion.
|
||||
- TrailingToLeading: The progress bar will travel from trailing to leading as the progress nears completion.
|
||||
- BottomToTop: The progress bar will travel from the bottom to the top as the progress nears completion.
|
||||
- TopToBottom: The progress bar will travel from the top to the bottom as the progress nears completion.
|
||||
*/
|
||||
public enum M13ProgressBarProgressDirection: Int, RawRepresentable {
|
||||
/// The progress bar will travel from leading to trailing as the progress nears completion.
|
||||
case LeadingToTrailing
|
||||
/// The progress bar will travel from trailing to leading as the progress nears completion.
|
||||
case TrailingToLeading
|
||||
/// The progress bar will travel from the bottom to the top as the progress nears completion.
|
||||
case BottomToTop
|
||||
/// The progress bar will travel from the top to the bottom as the progress nears completion.
|
||||
case TopToBottom
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
A simple progress bar similar to UIProgressBar, but with an indeterminate state.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressBar: M13ProgressView {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Appearance
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The corner radius of the progress bar.
|
||||
*/
|
||||
@IBInspectable public var cornerRadius: CGFloat = CGFloat.max {
|
||||
didSet {
|
||||
var appropiateCornerRadius: CGFloat = frame.size.width < frame.size.height ? frame.size.width / 2.0 : frame.size.height / 2.0
|
||||
appropiateCornerRadius = appropiateCornerRadius > cornerRadius ? cornerRadius : appropiateCornerRadius
|
||||
layer.cornerRadius = appropiateCornerRadius
|
||||
progressLayer.cornerRadius = appropiateCornerRadius
|
||||
indeterminateLayer.cornerRadius = appropiateCornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The secondary color of the progress view.
|
||||
*/
|
||||
override public var secondaryColor: UIColor {
|
||||
didSet {
|
||||
layer.backgroundColor = secondaryColor.CGColor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The primary color when the progress view is in the success state.
|
||||
*/
|
||||
override public var successColor: UIColor {
|
||||
didSet {
|
||||
if state == M13ProgressViewState.Success {
|
||||
progressLayer.backgroundColor = successColor.CGColor
|
||||
indeterminateLayer.backgroundColor = successColor.CGColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The primary color when the progress view is in the failure state.
|
||||
*/
|
||||
override public var failureColor: UIColor {
|
||||
didSet {
|
||||
if state == M13ProgressViewState.Failure {
|
||||
progressLayer.backgroundColor = failureColor.CGColor
|
||||
indeterminateLayer.backgroundColor = failureColor.CGColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The direction the progress bar travels in as the progress nears completion.
|
||||
*/
|
||||
@IBInspectable public var progressDirection: M13ProgressBarProgressDirection = M13ProgressBarProgressDirection.LeadingToTrailing {
|
||||
didSet {
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The layer that makes up the progress bar.
|
||||
*/
|
||||
internal var progressLayer: CALayer = CALayer()
|
||||
|
||||
/**
|
||||
The layer that makes up the indeterminate progress bar.
|
||||
*/
|
||||
internal var indeterminateLayer: CAShapeLayer = CAShapeLayer()
|
||||
|
||||
override public var indeterminate: Bool {
|
||||
didSet {
|
||||
// Add the indeterminate layer.
|
||||
if indeterminate && indeterminateLayer.superlayer == nil {
|
||||
progressLayer.removeFromSuperlayer()
|
||||
layer.addSublayer(indeterminateLayer)
|
||||
}
|
||||
|
||||
// Add the progress layer
|
||||
if !indeterminate && progressLayer.superlayer == nil {
|
||||
indeterminateLayer.removeFromSuperlayer()
|
||||
layer.addSublayer(progressLayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("cornerRadius") {
|
||||
cornerRadius = CGFloat(aDecoder.decodeDoubleForKey("cornerRadius"))
|
||||
}
|
||||
if aDecoder.containsValueForKey("progressDirection") {
|
||||
if let direction = M13ProgressBarProgressDirection(rawValue: aDecoder.decodeIntegerForKey("progressDirection")) {
|
||||
progressDirection = direction
|
||||
}
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
private func sharedSetup() {
|
||||
// Set the defaults.
|
||||
self.clipsToBounds = true
|
||||
|
||||
layer.cornerRadius = cornerRadius
|
||||
layer.backgroundColor = secondaryColor.CGColor
|
||||
|
||||
progressLayer.cornerRadius = cornerRadius
|
||||
indeterminateLayer.cornerRadius = cornerRadius
|
||||
progressLayer.backgroundColor = tintColor.CGColor
|
||||
indeterminateLayer.backgroundColor = tintColor.CGColor
|
||||
|
||||
// Disable default animations
|
||||
progressLayer.actions = [
|
||||
"frame": NSNull(),
|
||||
"anchorPoint": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
"cornerRadius": NSNull()
|
||||
]
|
||||
indeterminateLayer.actions = [
|
||||
"frame": NSNull(),
|
||||
"anchorPoint": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
"cornerRadius": NSNull()
|
||||
]
|
||||
|
||||
|
||||
// Add the layers
|
||||
self.layer.addSublayer(progressLayer)
|
||||
|
||||
// Set the progress and indeterminate animations.
|
||||
weak var weakSelf: M13ProgressBar? = self;
|
||||
progressUpdate = {() -> Void in
|
||||
|
||||
if let weakSelf = weakSelf {
|
||||
// Get the frame of the progress layer
|
||||
var progressFrame: CGRect = CGRectZero
|
||||
switch weakSelf.progressDirection {
|
||||
case .LeadingToTrailing:
|
||||
let xPosition = UIView.userInterfaceLayoutDirectionForSemanticContentAttribute(UISemanticContentAttribute.Spatial) == UIUserInterfaceLayoutDirection.LeftToRight ? 0.0 : weakSelf.frame.size.width - (weakSelf.frame.size.width * weakSelf.progress)
|
||||
progressFrame = CGRectMake(xPosition, 0.0, weakSelf.frame.size.width * weakSelf.progress, weakSelf.frame.size.height)
|
||||
break
|
||||
case .TrailingToLeading:
|
||||
let xPosition = UIView.userInterfaceLayoutDirectionForSemanticContentAttribute(UISemanticContentAttribute.Spatial) == UIUserInterfaceLayoutDirection.RightToLeft ? 0.0 : weakSelf.frame.size.width - (weakSelf.frame.size.width * weakSelf.progress)
|
||||
progressFrame = CGRectMake(xPosition, 0.0, weakSelf.frame.size.width * weakSelf.progress, weakSelf.frame.size.height)
|
||||
break
|
||||
case .BottomToTop:
|
||||
progressFrame = CGRectMake(0.0, weakSelf.frame.size.height - (weakSelf.frame.size.height * weakSelf.progress), weakSelf.frame.size.width, weakSelf.frame.size.height * weakSelf.progress)
|
||||
break
|
||||
case .TopToBottom:
|
||||
progressFrame = CGRectMake(0.0, 0.0, weakSelf.frame.size.width, weakSelf.frame.size.height * weakSelf.progress)
|
||||
break
|
||||
}
|
||||
weakSelf.progressLayer.frame = progressFrame
|
||||
}
|
||||
}
|
||||
|
||||
indeterminateUpdate = {(frameDuration: CFTimeInterval) -> Void in
|
||||
|
||||
if let weakSelf = weakSelf {
|
||||
|
||||
let horizontallyTraveling: Bool = weakSelf.progressDirection == M13ProgressBarProgressDirection.LeadingToTrailing || weakSelf.progressDirection == M13ProgressBarProgressDirection.TrailingToLeading
|
||||
|
||||
let barPosition: CGFloat = horizontallyTraveling ? weakSelf.indeterminateLayer.frame.origin.x : weakSelf.indeterminateLayer.frame.origin.y
|
||||
let barLength: CGFloat = horizontallyTraveling ? weakSelf.frame.size.width * 0.2 : weakSelf.frame.size.height * 0.2
|
||||
|
||||
let totalTravelDistance: CGFloat = horizontallyTraveling ? weakSelf.frame.size.width + (2.0 * barLength) : weakSelf.frame.size.height + (2.0 * barLength)
|
||||
let totalAnimationFrames: CGFloat = CGFloat(weakSelf.indeterminateAnimationDuration) / CGFloat(frameDuration)
|
||||
let travelDelta: CGFloat = totalTravelDistance / totalAnimationFrames
|
||||
|
||||
// Set the new frame of the bar: either move it by the travel delta, or move it back to the begining.
|
||||
switch weakSelf.progressDirection {
|
||||
case .LeadingToTrailing:
|
||||
let leftToRight: Bool = UIView.userInterfaceLayoutDirectionForSemanticContentAttribute(UISemanticContentAttribute.Spatial) == UIUserInterfaceLayoutDirection.LeftToRight
|
||||
if leftToRight {
|
||||
if barPosition >= weakSelf.frame.size.width {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(-barLength, 0.0, barLength, weakSelf.frame.size.height)
|
||||
} else {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(weakSelf.indeterminateLayer.frame.origin.x + travelDelta, 0.0, barLength, weakSelf.frame.size.height)
|
||||
}
|
||||
} else {
|
||||
if barPosition <= -barLength {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(weakSelf.frame.size.width, 0.0, barLength, weakSelf.frame.size.height)
|
||||
} else {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(weakSelf.indeterminateLayer.frame.origin.x - travelDelta, 0.0, barLength, weakSelf.frame.size.height)
|
||||
}
|
||||
}
|
||||
break
|
||||
case .TrailingToLeading:
|
||||
var rightToLeft: Bool = UIView.userInterfaceLayoutDirectionForSemanticContentAttribute(UISemanticContentAttribute.Spatial) == UIUserInterfaceLayoutDirection.RightToLeft
|
||||
if rightToLeft {
|
||||
if barPosition <= -barLength {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(weakSelf.frame.size.width, 0.0, barLength, weakSelf.frame.size.height)
|
||||
} else {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(weakSelf.indeterminateLayer.frame.origin.x - travelDelta, 0.0, barLength, weakSelf.frame.size.height)
|
||||
}
|
||||
} else {
|
||||
if barPosition >= weakSelf.frame.size.width {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(-barLength, 0.0, barLength, weakSelf.frame.size.height)
|
||||
} else {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(weakSelf.indeterminateLayer.frame.origin.x + travelDelta, 0.0, barLength, weakSelf.frame.size.height)
|
||||
}
|
||||
}
|
||||
break
|
||||
case .BottomToTop:
|
||||
if barPosition <= -barLength {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(0.0, weakSelf.frame.size.height, weakSelf.frame.size.width, barLength)
|
||||
} else {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(0.0, weakSelf.indeterminateLayer.frame.origin.y - travelDelta, weakSelf.frame.size.width, barLength)
|
||||
}
|
||||
break
|
||||
case .TopToBottom:
|
||||
if barPosition >= weakSelf.frame.size.height {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(0.0, -barLength, weakSelf.frame.size.width, barLength)
|
||||
} else {
|
||||
weakSelf.indeterminateLayer.frame = CGRectMake(0.0, weakSelf.indeterminateLayer.frame.origin.y + travelDelta, weakSelf.frame.size.width, barLength)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeDouble(Double(cornerRadius), forKey: "cornerRadius")
|
||||
aCoder.encodeInteger(progressDirection.rawValue, forKey: "progressDirection")
|
||||
}
|
||||
|
||||
public override func prepareForInterfaceBuilder() {
|
||||
sharedSetup()
|
||||
super.prepareForInterfaceBuilder()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
public override func setState(state: M13ProgressViewState, animated: Bool) {
|
||||
super.setState(state, animated: animated)
|
||||
|
||||
if !animated {
|
||||
switch state {
|
||||
case .Normal:
|
||||
progressLayer.backgroundColor = tintColor.CGColor
|
||||
indeterminateLayer.backgroundColor = tintColor.CGColor
|
||||
break
|
||||
case .Success:
|
||||
progressLayer.backgroundColor = successColor.CGColor
|
||||
indeterminateLayer.backgroundColor = successColor.CGColor
|
||||
break
|
||||
case .Failure:
|
||||
progressLayer.backgroundColor = failureColor.CGColor
|
||||
indeterminateLayer.backgroundColor = failureColor.CGColor
|
||||
break
|
||||
}
|
||||
} else {
|
||||
let colorAnimation: CABasicAnimation = CABasicAnimation(keyPath: "backgroundColor")
|
||||
colorAnimation.fromValue = progressLayer.backgroundColor!
|
||||
colorAnimation.fillMode = kCAFillModeForwards
|
||||
colorAnimation.removedOnCompletion = false
|
||||
colorAnimation.duration = animationDuration
|
||||
|
||||
var toColor: UIColor = tintColor
|
||||
switch state {
|
||||
case .Normal:
|
||||
toColor = tintColor
|
||||
break
|
||||
case .Success:
|
||||
toColor = successColor
|
||||
break
|
||||
case .Failure:
|
||||
toColor = failureColor
|
||||
break
|
||||
}
|
||||
|
||||
colorAnimation.toValue = toColor.CGColor
|
||||
progressLayer.addAnimation(colorAnimation, forKey: "backgroundColor")
|
||||
indeterminateLayer.addAnimation(colorAnimation, forKey: "backgroundColor")
|
||||
progressLayer.backgroundColor = toColor.CGColor
|
||||
indeterminateLayer.backgroundColor = toColor.CGColor
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func intrinsicContentSize() -> CGSize {
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric)
|
||||
}
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
//Update the corner radius
|
||||
var appropiateCornerRadius: CGFloat = frame.size.width < frame.size.height ? frame.size.width / 2.0 : frame.size.height / 2.0
|
||||
appropiateCornerRadius = appropiateCornerRadius > cornerRadius ? cornerRadius : appropiateCornerRadius
|
||||
layer.cornerRadius = appropiateCornerRadius
|
||||
progressLayer.cornerRadius = appropiateCornerRadius
|
||||
indeterminateLayer.cornerRadius = appropiateCornerRadius
|
||||
//Update progress frame
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Other
|
||||
//-------------------------------
|
||||
|
||||
public override func tintColorDidChange() {
|
||||
super.tintColorDidChange()
|
||||
progressLayer.backgroundColor = tintColor.CGColor
|
||||
indeterminateLayer.backgroundColor = tintColor.CGColor
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
//
|
||||
// M13ProgressCircular.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible directions a circular progress indicator can travel in.
|
||||
|
||||
- Clockwise: The progress ring will travel clockwise as the progress nears completion.
|
||||
- CounterClockwise: The progress ring will travel counter-clockwise as the progress nears completion.
|
||||
*/
|
||||
public enum M13ProgressCircularProgressDirection: Int, RawRepresentable {
|
||||
/// The progress ring will travel clockwise as the progress nears completion.
|
||||
case Clockwise
|
||||
/// The progress ring will travel counter-clockwise as the progress nears completion.
|
||||
case CounterClockwise
|
||||
}
|
||||
|
||||
/**
|
||||
Base class for circular progress views.
|
||||
Ring and Pie progress views are derived from this class. Do not instantiate directly.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressCircular: M13ProgressView {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The direction the progress bar travels in as the progress nears completion.
|
||||
*/
|
||||
@IBInspectable public var progressDirection: M13ProgressCircularProgressDirection = .Clockwise {
|
||||
didSet {
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var backgroundRingWidth :Int = 0 {
|
||||
didSet {
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Property Overrides
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The secondary color of the progress view.
|
||||
*/
|
||||
override public var secondaryColor: UIColor {
|
||||
didSet {
|
||||
indeterminateLayer.strokeColor = secondaryColor.CGColor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The primary color when the progress view is in the success state.
|
||||
*/
|
||||
override public var successColor: UIColor {
|
||||
didSet {
|
||||
if state == .Success {
|
||||
iconLayer.fillColor = successColor.CGColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The primary color when the progress view is in the failure state.
|
||||
*/
|
||||
override public var failureColor: UIColor {
|
||||
didSet {
|
||||
if state == .Failure {
|
||||
iconLayer.fillColor = failureColor.CGColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layers
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The layer that makes up the progress ring.
|
||||
*/
|
||||
internal var progressLayer: CAShapeLayer = CAShapeLayer()
|
||||
|
||||
/**
|
||||
The layer that makes up the indeterminate ring, and the background for the progress ring.
|
||||
*/
|
||||
internal var indeterminateLayer: CAShapeLayer = CAShapeLayer()
|
||||
|
||||
/**
|
||||
The layer that is used to render icons for success or failure.
|
||||
*/
|
||||
internal var iconLayer: CAShapeLayer = CAShapeLayer()
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Protected Variables
|
||||
//-------------------------------
|
||||
|
||||
/** The starting angle for drawing the indeterminate animation ring. */
|
||||
internal var indeterminateAnimationAngle :CGFloat = 0
|
||||
/** Ring widths after validation and bounds adjustments */
|
||||
internal var adjustedBackgroundRingWidth :CGFloat = 0
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("progressDirection") {
|
||||
if let direction = M13ProgressCircularProgressDirection(rawValue: aDecoder.decodeIntegerForKey("progressDirection")) {
|
||||
progressDirection = direction
|
||||
}
|
||||
}
|
||||
if aDecoder.containsValueForKey("backgroundRingWidth") {
|
||||
backgroundRingWidth = aDecoder.decodeIntegerForKey("backgroundRingWidth")
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
internal func sharedSetup() {
|
||||
// Set the defaults.
|
||||
self.clipsToBounds = false
|
||||
layer.backgroundColor = UIColor.clearColor().CGColor
|
||||
|
||||
// Set up the indeterminate layer
|
||||
indeterminateLayer = CAShapeLayer()
|
||||
indeterminateLayer.backgroundColor = UIColor.clearColor().CGColor
|
||||
indeterminateLayer.strokeColor = secondaryColor.CGColor
|
||||
indeterminateLayer.fillColor = nil
|
||||
indeterminateLayer.lineCap = kCALineCapRound
|
||||
|
||||
// Set up the progress layer
|
||||
progressLayer = CAShapeLayer()
|
||||
progressLayer.backgroundColor = UIColor.clearColor().CGColor
|
||||
progressLayer.strokeColor = nil
|
||||
progressLayer.fillColor = tintColor.CGColor
|
||||
progressLayer.lineCap = kCALineCapButt
|
||||
|
||||
adjustBackgroundRingWidth()
|
||||
|
||||
// Set up the icon layer
|
||||
iconLayer = CAShapeLayer()
|
||||
iconLayer.backgroundColor = UIColor.clearColor().CGColor
|
||||
iconLayer.strokeColor = nil
|
||||
iconLayer.fillColor = nil
|
||||
iconLayer.lineCap = kCALineCapButt
|
||||
|
||||
// Disable default animations
|
||||
progressLayer.actions = [
|
||||
"frame": NSNull(),
|
||||
"anchorPoint": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
]
|
||||
indeterminateLayer.actions = [
|
||||
"frame": NSNull(),
|
||||
"anchorPoint": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
]
|
||||
iconLayer.actions = [
|
||||
"frame": NSNull(),
|
||||
"anchorPoint": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
]
|
||||
|
||||
// Add the layers
|
||||
layer.addSublayer(indeterminateLayer)
|
||||
layer.addSublayer(progressLayer)
|
||||
layer.addSublayer(iconLayer)
|
||||
|
||||
// Be sure to implement progressUpdate() and indeterminateUpdate in child classes.
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeInteger(progressDirection.rawValue, forKey: "progressDirection")
|
||||
aCoder.encodeInteger(backgroundRingWidth, forKey: "backgroundRingWidth")
|
||||
super.encodeWithCoder(aCoder)
|
||||
}
|
||||
|
||||
public override func prepareForInterfaceBuilder() {
|
||||
sharedSetup()
|
||||
super.prepareForInterfaceBuilder()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
public override func setState(state: M13ProgressViewState, animated: Bool) {
|
||||
super.setState(state, animated: animated)
|
||||
|
||||
switch state {
|
||||
case .Normal:
|
||||
hideIcon()
|
||||
break
|
||||
case .Success:
|
||||
drawSuccess()
|
||||
break
|
||||
case .Failure:
|
||||
drawFailure()
|
||||
break
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func intrinsicContentSize() -> CGSize {
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric)
|
||||
}
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
adjustBackgroundRingWidth()
|
||||
|
||||
// Update progress frame
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
public func adjustBackgroundRingWidth()
|
||||
{
|
||||
if backgroundRingWidth > 0 {
|
||||
adjustedBackgroundRingWidth = CGFloat(backgroundRingWidth)
|
||||
} else {
|
||||
adjustedBackgroundRingWidth = max(self.bounds.size.width * 0.025, 1.0)
|
||||
}
|
||||
indeterminateLayer.lineWidth = adjustedBackgroundRingWidth
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Draw Functions
|
||||
//-------------------------------
|
||||
|
||||
public func maxRadius() -> CGFloat
|
||||
{
|
||||
return min(self.bounds.size.width, self.bounds.size.height) / 2.0
|
||||
}
|
||||
|
||||
public func centerOfCircle() -> CGPoint
|
||||
{
|
||||
return CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0)
|
||||
}
|
||||
|
||||
public func createPieSlicePath(center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) -> UIBezierPath {
|
||||
let path = UIBezierPath()
|
||||
path.moveToPoint(center)
|
||||
path.addLineToPoint(CGPointMake(center.x + radius * cos(startAngle), center.y + radius * sin(startAngle)))
|
||||
path.addArcWithCenter(center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise)
|
||||
path.closePath()
|
||||
return path
|
||||
}
|
||||
|
||||
public func drawBackground()
|
||||
{
|
||||
// Draw a circle
|
||||
let center = centerOfCircle()
|
||||
let radius = maxRadius() - adjustedBackgroundRingWidth / 2.0
|
||||
let path = UIBezierPath()
|
||||
path.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: 2.0 * CGFloat(M_PI), clockwise: true)
|
||||
indeterminateLayer.path = path.CGPath
|
||||
}
|
||||
|
||||
public func drawSuccess()
|
||||
{
|
||||
// Draw relative to a base size and percentage, that way the check can be drawn for any size.
|
||||
let radius = maxRadius()
|
||||
let size = radius * 0.3
|
||||
|
||||
// Create the path for the Checkmark
|
||||
let path = UIBezierPath()
|
||||
path.moveToPoint(CGPointMake(0, 0))
|
||||
path.addLineToPoint(CGPointMake(0, size * 2))
|
||||
path.addLineToPoint(CGPointMake(size * 3, size * 2))
|
||||
path.addLineToPoint(CGPointMake(size * 3, size))
|
||||
path.addLineToPoint(CGPointMake(size, size))
|
||||
path.addLineToPoint(CGPointMake(size, 0))
|
||||
path.closePath()
|
||||
|
||||
// Rotate it through -45 degrees...
|
||||
path.applyTransform(CGAffineTransformMakeRotation(CGFloat(-M_PI_4)))
|
||||
|
||||
// Center it
|
||||
path.applyTransform(CGAffineTransformMakeTranslation(radius * 0.46, radius * 1.02))
|
||||
|
||||
// Set path and fill color
|
||||
iconLayer.path = path.CGPath
|
||||
iconLayer.fillColor = successColor.CGColor
|
||||
}
|
||||
|
||||
public func drawFailure()
|
||||
{
|
||||
// Calculate the size of the X
|
||||
let radius = maxRadius()
|
||||
let size = radius * 0.3
|
||||
|
||||
// Create the path for the X
|
||||
let path = UIBezierPath()
|
||||
path.moveToPoint(CGPointMake(size, 0))
|
||||
path.addLineToPoint(CGPointMake(2 * size, 0))
|
||||
path.addLineToPoint(CGPointMake(2 * size, size))
|
||||
path.addLineToPoint(CGPointMake(3 * size, size))
|
||||
path.addLineToPoint(CGPointMake(3 * size, 2 * size))
|
||||
path.addLineToPoint(CGPointMake(2 * size, 2 * size))
|
||||
path.addLineToPoint(CGPointMake(2 * size, 3 * size))
|
||||
path.addLineToPoint(CGPointMake(size, 3 * size))
|
||||
path.addLineToPoint(CGPointMake(size, 2 * size))
|
||||
path.addLineToPoint(CGPointMake(0, 2 * size))
|
||||
path.addLineToPoint(CGPointMake(0, size))
|
||||
path.addLineToPoint(CGPointMake(size, size))
|
||||
path.closePath()
|
||||
|
||||
// Center it
|
||||
path.applyTransform(CGAffineTransformMakeTranslation(radius - (1.5 * size), radius - (1.5 * size)))
|
||||
|
||||
// Rotate path
|
||||
let a = CGFloat(cos(M_PI_4))
|
||||
let b = CGFloat(sin(M_PI_4))
|
||||
let c = CGFloat(-sin(M_PI_4))
|
||||
let d = CGFloat(cos(M_PI_4))
|
||||
let tx = radius * CGFloat(1 - cos(M_PI_4) + sin(M_PI_4))
|
||||
let ty = radius * CGFloat(1 - sin(M_PI_4) - cos(M_PI_4))
|
||||
path.applyTransform(CGAffineTransformMake(a, b, c, d, tx, ty))
|
||||
|
||||
// Set path and fill color
|
||||
iconLayer.path = path.CGPath
|
||||
iconLayer.fillColor = failureColor.CGColor
|
||||
}
|
||||
|
||||
public func hideIcon()
|
||||
{
|
||||
iconLayer.path = nil
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Other
|
||||
//-------------------------------
|
||||
|
||||
public override func tintColorDidChange() {
|
||||
super.tintColorDidChange()
|
||||
progressLayer.fillColor = tintColor.CGColor
|
||||
progressLayer.strokeColor = nil
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
//
|
||||
// M13ProgressFilteredImage.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible filters that can be applied to a progress image.
|
||||
|
||||
- Blur: The image goes from blurry to in-focus as progress nears completion.
|
||||
- LightTunnel:
|
||||
- SepiaTone: The image goes from Sepia Tone to full-color as progress nears completion.
|
||||
*/
|
||||
public enum M13ProgressImageProgressFilter: Int, RawRepresentable {
|
||||
///
|
||||
case Blur
|
||||
///
|
||||
case LightTunnel
|
||||
///
|
||||
case SepiaTone
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
A progress view where progress is shown by changes in CIFilters.
|
||||
@note This progress bar does not have in indeterminate mode and does not respond to actions.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressFilteredImage: M13ProgressView {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The direction the progress bar travels in as the progress nears completion. (What direction the fill proceeds in.)
|
||||
*/
|
||||
@IBInspectable public var progressFilter: M13ProgressImageProgressFilter = .Blur {
|
||||
didSet {
|
||||
switch (progressFilter) {
|
||||
case .Blur:
|
||||
setBlurFilter()
|
||||
case .LightTunnel:
|
||||
setLightTunnelFilter()
|
||||
case .SepiaTone:
|
||||
setSepiaToneFilter()
|
||||
}
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The image to use when showing progress.
|
||||
*/
|
||||
@IBInspectable public var progressImage: UIImage! {
|
||||
didSet {
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Filter Variables
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The array of CIFilters to apply to the image.
|
||||
*/
|
||||
public var filters :[AnyObject] = []
|
||||
|
||||
/**
|
||||
The dictionaries of dictionaries that correspond to filter properties to be changed.
|
||||
NSArray
|
||||
|------ NSDictionary (Index matches the coresponding CIFilter in filters)
|
||||
| |---- "Parameter Key" -> NSDictionary
|
||||
| | |------ "Start Value" -> NSNumber
|
||||
| | |------ "End Value" -> NSNumber
|
||||
| |---- "Parameter Key" -> NSDictionary
|
||||
| |------ "Start Value" -> NSNumber
|
||||
| |------ "End Value" -> NSNumber
|
||||
|------ NSDictionary ...
|
||||
*/
|
||||
public var filterParameters :[ [String:AnyObject] ] = []
|
||||
|
||||
/**
|
||||
Keys for the filterParameters dictionary.
|
||||
*/
|
||||
public let FilterStartValuesKey = "StartValues"
|
||||
public let FilterEndValuesKey = "EndValues"
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Protected Variables
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The UIImageView that shows the progress image.
|
||||
*/
|
||||
internal var progressView: UIImageView!
|
||||
|
||||
/**
|
||||
Link to the display to keep animations in sync.
|
||||
*/
|
||||
internal var displayLink: CADisplayLink!
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("progressFilter") {
|
||||
if let filter = M13ProgressImageProgressFilter(rawValue: aDecoder.decodeIntegerForKey("progressFilter")) {
|
||||
progressFilter = filter
|
||||
}
|
||||
}
|
||||
if aDecoder.containsValueForKey("progressImage") {
|
||||
if let img = aDecoder.decodeObjectForKey("progressImage") as? UIImage {
|
||||
progressImage = img
|
||||
}
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
internal func sharedSetup() {
|
||||
// Set the defaults
|
||||
self.clipsToBounds = false
|
||||
layer.backgroundColor = UIColor.clearColor().CGColor
|
||||
|
||||
// Set the progress image view
|
||||
progressView = UIImageView(frame: self.bounds)
|
||||
progressView.contentMode = .ScaleAspectFit
|
||||
addSubview(progressView)
|
||||
|
||||
// Layout
|
||||
layoutSubviews()
|
||||
|
||||
// Set the progress animation.
|
||||
weak var weakSelf: M13ProgressFilteredImage? = self
|
||||
progressUpdate = {() -> Void in
|
||||
if let retainedSelf = weakSelf {
|
||||
retainedSelf.progressView.image = retainedSelf.createImageForCurrentProgress()
|
||||
}
|
||||
}
|
||||
|
||||
// There is no indeterminate animation.
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeInteger(progressFilter.rawValue, forKey: "progressFilter")
|
||||
aCoder.encodeObject(progressImage)
|
||||
super.encodeWithCoder(aCoder)
|
||||
}
|
||||
|
||||
public override func prepareForInterfaceBuilder() {
|
||||
sharedSetup()
|
||||
super.prepareForInterfaceBuilder()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Filters
|
||||
//-------------------------------
|
||||
|
||||
internal func setBlurFilter()
|
||||
{
|
||||
guard let blurFilter = CIFilter(name: "CIGaussianBlur") else {
|
||||
return
|
||||
}
|
||||
|
||||
blurFilter.setDefaults()
|
||||
|
||||
filters = [ blurFilter ]
|
||||
|
||||
filterParameters = [
|
||||
[
|
||||
"inputRadius" : [
|
||||
FilterStartValuesKey : CGFloat(100.0),
|
||||
FilterEndValuesKey : CGFloat(0.0)
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
internal func setSepiaToneFilter()
|
||||
{
|
||||
guard let sepiaFilter = CIFilter(name: "CISepiaTone") else {
|
||||
return
|
||||
}
|
||||
|
||||
sepiaFilter.setDefaults()
|
||||
|
||||
// Set filter intensity
|
||||
sepiaFilter.setValue(1.0, forKey: kCIInputIntensityKey)
|
||||
|
||||
filters = [ sepiaFilter ]
|
||||
|
||||
filterParameters = [
|
||||
[
|
||||
kCIInputIntensityKey : [
|
||||
FilterStartValuesKey : CGFloat(1.0),
|
||||
FilterEndValuesKey : CGFloat(0.0)
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
internal func setLightTunnelFilter()
|
||||
{
|
||||
if false { "TODO: CILightTunnel filter does not work yet" }
|
||||
|
||||
guard let lightTunnelFilter = CIFilter(name: "CILightTunnel") else {
|
||||
return
|
||||
}
|
||||
|
||||
lightTunnelFilter.setDefaults()
|
||||
|
||||
// Get center
|
||||
let center = CIVector(CGPoint: CGPointMake(progressImage.size.width / 2.0, progressImage.size.height / 2.0))
|
||||
lightTunnelFilter.setValue(center, forKey: "inputCenter")
|
||||
|
||||
filters = [ lightTunnelFilter ]
|
||||
|
||||
filterParameters = [
|
||||
[
|
||||
"inputRotation" : [
|
||||
FilterStartValuesKey : CGFloat(10.0),
|
||||
FilterEndValuesKey : CGFloat(0.0)
|
||||
],
|
||||
"inputRadius" : [
|
||||
FilterStartValuesKey : CGFloat(20.0),
|
||||
FilterEndValuesKey : CGFloat(0.0)
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func intrinsicContentSize() -> CGSize {
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric)
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Draw Functions
|
||||
//-------------------------------
|
||||
|
||||
public func createImageForCurrentProgress() -> UIImage? {
|
||||
guard let cgimage = progressImage.CGImage else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the base CIImage
|
||||
var ciimage = CIImage(CGImage: cgimage)
|
||||
// Change the values of the CIFilters before drawing
|
||||
for (var i = 0; i < filters.count; ++i) {
|
||||
let filter = filters[i]
|
||||
// For each filter
|
||||
let parameters = filterParameters[i]
|
||||
// For each parameter
|
||||
for parameterKey in parameters.keys {
|
||||
// Retrieve the values
|
||||
let obj = parameters[parameterKey]
|
||||
if let parameterDict = obj as? [String:CGFloat] {
|
||||
if let startValue = parameterDict[FilterStartValuesKey], let endValue = parameterDict[FilterEndValuesKey] {
|
||||
// Calculate the current value
|
||||
let value = startValue + ((endValue - startValue) * self.progress)
|
||||
// Set the value
|
||||
filter.setValue(value, forKey: parameterKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the input image
|
||||
filter.setValue(ciimage, forKey: kCIInputImageKey)
|
||||
if let img0 = filter.outputImage, let img1 = img0 {
|
||||
ciimage = img1
|
||||
}
|
||||
}
|
||||
return UIImage(CIImage: ciimage)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
//
|
||||
// M13ProgressImage.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
A progress bar where progress is shown by cutting an image.
|
||||
@note This progress bar does not have in indeterminate mode and does not respond to actions.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressImage: M13ProgressView {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The direction the progress bar travels in as the progress nears completion. (What direction the fill proceeds in.)
|
||||
*/
|
||||
@IBInspectable public var progressDirection: M13ProgressBarProgressDirection = .LeadingToTrailing {
|
||||
didSet {
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The image to use when showing progress.
|
||||
*/
|
||||
@IBInspectable public var progressImage: UIImage! {
|
||||
didSet {
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Whether or not to draw the greyscale background.
|
||||
*/
|
||||
@IBInspectable public var drawGreyscaleBackground: Bool = true {
|
||||
didSet {
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Protected Variables
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The UIImageView that shows the progress image.
|
||||
*/
|
||||
internal var progressView: UIImageView!
|
||||
|
||||
/**
|
||||
Link to the display to keep animations in sync.
|
||||
*/
|
||||
internal var displayLink: CADisplayLink!
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("progressDirection") {
|
||||
if let direction = M13ProgressBarProgressDirection(rawValue: aDecoder.decodeIntegerForKey("progressDirection")) {
|
||||
progressDirection = direction
|
||||
}
|
||||
}
|
||||
if aDecoder.containsValueForKey("progressImage") {
|
||||
if let img = aDecoder.decodeObjectForKey("progressImage") as? UIImage {
|
||||
progressImage = img
|
||||
}
|
||||
}
|
||||
if aDecoder.containsValueForKey("drawGreyscaleBackground") {
|
||||
drawGreyscaleBackground = aDecoder.decodeBoolForKey("drawGreyscaleBackground")
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
internal func sharedSetup() {
|
||||
// Set the defaults
|
||||
self.clipsToBounds = false
|
||||
layer.backgroundColor = UIColor.clearColor().CGColor
|
||||
|
||||
// Set the progress image view
|
||||
progressView = UIImageView(frame: self.bounds)
|
||||
progressView.contentMode = .ScaleAspectFit
|
||||
addSubview(progressView)
|
||||
|
||||
// Layout
|
||||
layoutSubviews()
|
||||
|
||||
// Set the progress animation.
|
||||
weak var weakSelf: M13ProgressImage? = self
|
||||
progressUpdate = {() -> Void in
|
||||
if let retainedSelf = weakSelf {
|
||||
retainedSelf.progressView.image = retainedSelf.createImageForCurrentProgress()
|
||||
}
|
||||
}
|
||||
|
||||
// There is no indeterminate animation.
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeInteger(progressDirection.rawValue, forKey: "progressDirection")
|
||||
aCoder.encodeObject(progressImage, forKey: "progressImage")
|
||||
aCoder.encodeBool(drawGreyscaleBackground, forKey: "drawGreyscaleBackground")
|
||||
super.encodeWithCoder(aCoder)
|
||||
}
|
||||
|
||||
public override func prepareForInterfaceBuilder() {
|
||||
sharedSetup()
|
||||
super.prepareForInterfaceBuilder()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func intrinsicContentSize() -> CGSize {
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric)
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Draw Functions
|
||||
//-------------------------------
|
||||
|
||||
public func createImageForCurrentProgress() -> UIImage?
|
||||
{
|
||||
// Create image rectangle with current image width/height
|
||||
let imageRect = CGRectMake(0, 0, progressImage.size.width * progressImage.scale, progressImage.size.height * progressImage.scale)
|
||||
|
||||
let width = imageRect.size.width
|
||||
let height = imageRect.size.height
|
||||
|
||||
// The pixels will be painted to this array
|
||||
let BPP = 4 // 4 bytes per pixel (alpha-red-green-blue)
|
||||
let memsize = Int(width) * Int(height)
|
||||
let pixels = UnsafeMutablePointer<UInt32>.alloc(memsize)
|
||||
// Clear the pixels so any transparency is preserved
|
||||
pixels.initializeFrom(Repeat(count: memsize, repeatedValue: 0))
|
||||
|
||||
//Create a context with ARGB pixels
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedLast.rawValue
|
||||
let context = CGBitmapContextCreate(pixels, Int(width), Int(height), 8, Int(width) * BPP, colorSpace, bitmapInfo)
|
||||
|
||||
// Paint the bitmap to our context which will fill in the pixels array
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), progressImage.CGImage)
|
||||
|
||||
// Calculate the ranges to make greyscale or transparent
|
||||
var xFrom: Int = 0
|
||||
var xTo : Int = Int(width)
|
||||
var yFrom: Int = 0
|
||||
var yTo : Int = Int(height)
|
||||
|
||||
if (progressDirection == .BottomToTop) {
|
||||
yTo = Int(height * (1 - self.progress))
|
||||
} else if (progressDirection == .TopToBottom) {
|
||||
yFrom = Int(height * self.progress)
|
||||
} else if (progressDirection == .LeadingToTrailing) {
|
||||
xFrom = Int(width * self.progress)
|
||||
} else if (progressDirection == .TrailingToLeading) {
|
||||
xTo = Int(width * (1 - self.progress))
|
||||
}
|
||||
|
||||
for (var x = xFrom; x < xTo; ++x) {
|
||||
for (var y = yFrom; y < yTo; ++y) {
|
||||
// Get the pixel
|
||||
let index = (y * Int(width) + x)
|
||||
// Convert
|
||||
if drawGreyscaleBackground {
|
||||
|
||||
let value = pixels[index]
|
||||
|
||||
// Mask out the alpha component
|
||||
let alpha = value & 0x000000FF
|
||||
|
||||
// Mask out the red-green-blue component values, and bitshift them down to one byte
|
||||
let r0 = UInt8((value & 0x0000FF00) >> 8)
|
||||
let g0 = UInt8((value & 0x00FF0000) >> 16)
|
||||
let b0 = UInt8((value & 0xFF000000) >> 24)
|
||||
|
||||
if false { "TODO: grayscale has a very green hue to it -- should be more gray" }
|
||||
|
||||
// Convert each red-green-blue component value to grayscale using luma coding
|
||||
// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
|
||||
let r1 = UInt8(0.299 * CGFloat(r0))
|
||||
let g1 = UInt8(0.587 * CGFloat(g0))
|
||||
let b1 = UInt8(0.114 * CGFloat(b0))
|
||||
|
||||
// Set the current pixel to gray
|
||||
// Bitshift the red-green-blue component values left so we can OR them into a 4-byte pixel value
|
||||
let r2 = UInt32(r1) << 8
|
||||
let g2 = UInt32(g1) << 16
|
||||
let b2 = UInt32(b1) << 24
|
||||
pixels[index] = alpha | r2 | g2 | b2
|
||||
} else {
|
||||
// Convert the current pixel to transparent
|
||||
pixels[index] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We're done with the pixel array, so release it
|
||||
pixels.dealloc(memsize)
|
||||
|
||||
// Create a new CGImageRef from our context with the modified pixels, then
|
||||
// Make a new UIImage to return
|
||||
if let image = CGBitmapContextCreateImage(context) {
|
||||
return UIImage(CGImage: image, scale: progressImage.scale, orientation: .Up)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
//
|
||||
// M13ProgressPie.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
A progress view that shows progress with a pie chart.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressPie: M13ProgressCircular {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override internal func sharedSetup() {
|
||||
super.sharedSetup()
|
||||
|
||||
// Set the defaults.
|
||||
self.clipsToBounds = false
|
||||
layer.backgroundColor = UIColor.clearColor().CGColor
|
||||
|
||||
// Set the progress animation.
|
||||
weak var weakSelf: M13ProgressPie? = self
|
||||
progressUpdate = {() -> Void in
|
||||
|
||||
if let retainedSelf = weakSelf {
|
||||
|
||||
// Create parameters to draw ring
|
||||
var startAngle = CGFloat(-M_PI_2)
|
||||
var endAngle = startAngle + (2.0 * CGFloat(M_PI) * retainedSelf.progress)
|
||||
|
||||
let clockwise = (retainedSelf.progressDirection == .Clockwise)
|
||||
if !clockwise {
|
||||
// For counter-clockwise, subtract angles from 360 degrees, and swap start-end
|
||||
let tmp = CGFloat(M_PI) - startAngle
|
||||
startAngle = CGFloat(M_PI) - endAngle
|
||||
endAngle = tmp
|
||||
}
|
||||
|
||||
// Draw background
|
||||
retainedSelf.drawBackground()
|
||||
|
||||
// Draw progress ring
|
||||
let center = retainedSelf.centerOfCircle()
|
||||
let radius = retainedSelf.maxRadius()
|
||||
let path = retainedSelf.createPieSlicePath(center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
retainedSelf.progressLayer.path = path.CGPath
|
||||
}
|
||||
}
|
||||
|
||||
// Set the indeterminate animation.
|
||||
indeterminateUpdate = {(frameDuration: CFTimeInterval) -> Void in
|
||||
|
||||
if let retainedSelf = weakSelf {
|
||||
|
||||
// Create parameters to draw progress
|
||||
let startAngle = CGFloat(retainedSelf.indeterminateAnimationAngle)
|
||||
let endAngle = startAngle + CGFloat(M_PI) * 2.0 * 0.8 // 80% of a circle
|
||||
|
||||
let deltaAngle = CGFloat(frameDuration * 2.0 * M_PI)
|
||||
if retainedSelf.progressDirection == .CounterClockwise {
|
||||
// CounterClockwise
|
||||
retainedSelf.indeterminateAnimationAngle -= deltaAngle
|
||||
} else {
|
||||
// Clockwise
|
||||
retainedSelf.indeterminateAnimationAngle += deltaAngle
|
||||
}
|
||||
|
||||
// Draw background
|
||||
retainedSelf.drawBackground()
|
||||
|
||||
// Draw path
|
||||
let center = retainedSelf.centerOfCircle()
|
||||
let radius = retainedSelf.maxRadius()
|
||||
let path = retainedSelf.createPieSlicePath(center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
|
||||
retainedSelf.progressLayer.path = path.CGPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
//
|
||||
// M13ProgressRing.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
A progress view stylized similarly to the iOS 7 App store progress view.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressRing: M13ProgressCircular {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
@IBInspectable public var percentage: Bool = false {
|
||||
didSet {
|
||||
percentageLabel.hidden = !percentage
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var progressRingWidth :Int = 0 {
|
||||
didSet {
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Property Overrides
|
||||
//-------------------------------
|
||||
|
||||
override public var indeterminate: Bool {
|
||||
didSet {
|
||||
let tmp = indeterminate
|
||||
super.indeterminate = tmp
|
||||
if indeterminate {
|
||||
progressLayer.hidden = true
|
||||
percentageLabel.hidden = true
|
||||
} else {
|
||||
progressLayer.hidden = false
|
||||
percentageLabel.hidden = !percentage
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Protected Variables
|
||||
//-------------------------------
|
||||
|
||||
/** The number formatter to display the progress percentage. */
|
||||
internal var percentageFormatter: NSNumberFormatter!
|
||||
/** The label that shows the percentage. */
|
||||
internal var percentageLabel: UILabel!
|
||||
/** Ring widths after validation and bounds adjustments */
|
||||
internal var adjustedProgressRingWidth :CGFloat = 0
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("percentage") {
|
||||
percentage = aDecoder.decodeBoolForKey("percentage")
|
||||
}
|
||||
if aDecoder.containsValueForKey("progressRingWidth") {
|
||||
progressRingWidth = aDecoder.decodeIntegerForKey("progressRingWidth")
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
internal override func sharedSetup() {
|
||||
super.sharedSetup()
|
||||
|
||||
// Set the defaults.
|
||||
self.clipsToBounds = false
|
||||
layer.backgroundColor = UIColor.clearColor().CGColor
|
||||
|
||||
// Set up the indeterminate layer
|
||||
indeterminateLayer.strokeColor = secondaryColor.CGColor
|
||||
indeterminateLayer.fillColor = nil
|
||||
|
||||
// Set up the progress layer
|
||||
progressLayer.strokeColor = tintColor.CGColor
|
||||
progressLayer.fillColor = nil
|
||||
|
||||
adjustProgressRingWidth()
|
||||
|
||||
// Set up the number formatter
|
||||
percentageFormatter = NSNumberFormatter()
|
||||
percentageFormatter.numberStyle = .PercentStyle
|
||||
|
||||
// Set the percentage label
|
||||
percentageLabel = UILabel(frame: self.bounds)
|
||||
percentageLabel.textAlignment = .Center
|
||||
percentageLabel.contentMode = .Center
|
||||
self.addSubview(percentageLabel)
|
||||
|
||||
// Set the progress animation.
|
||||
weak var weakSelf: M13ProgressRing? = self
|
||||
progressUpdate = {() -> Void in
|
||||
|
||||
if let retainedSelf = weakSelf {
|
||||
|
||||
// Create parameters to draw ring
|
||||
let clockwise = (retainedSelf.progressDirection == .Clockwise)
|
||||
var startAngle = CGFloat(-M_PI_2)
|
||||
var endAngle = startAngle + (2.0 * CGFloat(M_PI) * retainedSelf.progress)
|
||||
if !clockwise {
|
||||
// For counter-clockwise, subtract angles from 360 degrees, and swap start-end
|
||||
let tmp = CGFloat(M_PI) - startAngle
|
||||
startAngle = CGFloat(M_PI) - endAngle
|
||||
endAngle = tmp
|
||||
}
|
||||
|
||||
// Draw background
|
||||
retainedSelf.drawBackground()
|
||||
|
||||
// Draw progress ring
|
||||
let center = retainedSelf.centerOfCircle()
|
||||
let radius = retainedSelf.maxRadius() - retainedSelf.adjustedProgressRingWidth / 2.0
|
||||
let path = UIBezierPath()
|
||||
path.addArcWithCenter(center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
retainedSelf.progressLayer.path = path.CGPath
|
||||
|
||||
// Draw percentage
|
||||
if retainedSelf.percentage && retainedSelf.state == .Normal {
|
||||
retainedSelf.drawPercentage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the indeterminate animation.
|
||||
indeterminateUpdate = {(frameDuration: CFTimeInterval) -> Void in
|
||||
|
||||
if let retainedSelf = weakSelf {
|
||||
|
||||
retainedSelf.hidePercentage()
|
||||
|
||||
// Create parameters to draw progress
|
||||
let startAngle = CGFloat(retainedSelf.indeterminateAnimationAngle)
|
||||
let endAngle = startAngle + CGFloat(M_PI) * 2.0 * 0.8 // 80% of a circle
|
||||
|
||||
let deltaAngle = CGFloat(frameDuration * 2.0 * M_PI)
|
||||
if retainedSelf.progressDirection == .CounterClockwise {
|
||||
// CounterClockwise
|
||||
retainedSelf.indeterminateAnimationAngle -= deltaAngle
|
||||
} else {
|
||||
// Clockwise
|
||||
retainedSelf.indeterminateAnimationAngle += deltaAngle
|
||||
}
|
||||
|
||||
// Draw path
|
||||
let center = retainedSelf.centerOfCircle()
|
||||
let radius = retainedSelf.maxRadius() - retainedSelf.adjustedBackgroundRingWidth / 2.0
|
||||
let path = UIBezierPath()
|
||||
path.addArcWithCenter(center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
retainedSelf.indeterminateLayer.path = path.CGPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeBool(percentage, forKey: "percentage")
|
||||
aCoder.encodeInteger(progressRingWidth, forKey: "progressRingWidth")
|
||||
super.encodeWithCoder(aCoder)
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
public override func setState(state: M13ProgressViewState, animated: Bool) {
|
||||
super.setState(state, animated: animated)
|
||||
|
||||
var toColor1: UIColor = tintColor
|
||||
var toColor2: UIColor = secondaryColor
|
||||
switch state {
|
||||
case .Normal:
|
||||
hideIcon()
|
||||
if percentage {
|
||||
drawPercentage()
|
||||
}
|
||||
break
|
||||
case .Success:
|
||||
hidePercentage()
|
||||
drawSuccess()
|
||||
toColor1 = successColor
|
||||
if indeterminate {
|
||||
toColor2 = successColor
|
||||
}
|
||||
break
|
||||
case .Failure:
|
||||
hidePercentage()
|
||||
drawFailure()
|
||||
toColor1 = failureColor
|
||||
if indeterminate {
|
||||
toColor2 = failureColor
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if !animated {
|
||||
progressLayer.strokeColor = toColor1.CGColor
|
||||
indeterminateLayer.strokeColor = toColor2.CGColor
|
||||
} else {
|
||||
let colorAnimation1: CABasicAnimation = CABasicAnimation(keyPath: "strokeColor")
|
||||
colorAnimation1.fromValue = progressLayer.backgroundColor!
|
||||
colorAnimation1.fillMode = kCAFillModeForwards
|
||||
colorAnimation1.removedOnCompletion = false
|
||||
colorAnimation1.duration = animationDuration
|
||||
|
||||
let colorAnimation2: CABasicAnimation = CABasicAnimation(keyPath: "strokeColor")
|
||||
colorAnimation2.fromValue = indeterminateLayer.backgroundColor!
|
||||
colorAnimation2.fillMode = kCAFillModeForwards
|
||||
colorAnimation2.removedOnCompletion = false
|
||||
colorAnimation2.duration = animationDuration
|
||||
|
||||
colorAnimation1.toValue = toColor1.CGColor
|
||||
progressLayer.addAnimation(colorAnimation1, forKey: "strokeColor")
|
||||
progressLayer.strokeColor = toColor1.CGColor
|
||||
|
||||
colorAnimation2.toValue = toColor2.CGColor
|
||||
indeterminateLayer.addAnimation(colorAnimation2, forKey: "strokeColor")
|
||||
indeterminateLayer.strokeColor = toColor2.CGColor
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
adjustProgressRingWidth()
|
||||
|
||||
// Percentage label
|
||||
if percentage {
|
||||
percentageLabel.frame = self.bounds
|
||||
percentageLabel.font = UIFont.systemFontOfSize(self.bounds.size.width / 5)
|
||||
percentageLabel.textColor = tintColor
|
||||
}
|
||||
|
||||
// Update progress frame
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
public func adjustProgressRingWidth()
|
||||
{
|
||||
if progressRingWidth > 0 {
|
||||
adjustedProgressRingWidth = CGFloat(progressRingWidth)
|
||||
} else {
|
||||
adjustedProgressRingWidth = adjustedBackgroundRingWidth * 3.0
|
||||
}
|
||||
progressLayer.lineWidth = adjustedProgressRingWidth
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Draw Functions
|
||||
//-------------------------------
|
||||
|
||||
public func drawPercentage()
|
||||
{
|
||||
percentageLabel.text = percentageFormatter.stringFromNumber(self.progress)
|
||||
}
|
||||
|
||||
public func hidePercentage()
|
||||
{
|
||||
percentageLabel.text = ""
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Other
|
||||
//-------------------------------
|
||||
|
||||
public override func tintColorDidChange() {
|
||||
super.tintColorDidChange()
|
||||
progressLayer.fillColor = nil
|
||||
progressLayer.strokeColor = tintColor.CGColor
|
||||
percentageLabel.textColor = tintColor
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
//
|
||||
// M13ProgressSegmentedRing.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The segment boundary types.
|
||||
|
||||
- Wedge:
|
||||
- Rectangle:
|
||||
*/
|
||||
public enum M13ProgressViewSegmentedRingSegmentBoundaryType: Int, RawRepresentable {
|
||||
///
|
||||
case Wedge
|
||||
///
|
||||
case Rectangle
|
||||
}
|
||||
|
||||
/**
|
||||
Progress is shown by a ring split up into segments.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressSegmentedRing: M13ProgressRing {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The number of segments to display in the progress view.
|
||||
*/
|
||||
@IBInspectable public var numberOfSegments: Int = 10
|
||||
|
||||
/**
|
||||
The angle of the separation between the segments in radians.
|
||||
*/
|
||||
@IBInspectable public var segmentSeparationAngle :CGFloat = 0.1
|
||||
|
||||
/**
|
||||
The type of boundary between segments.
|
||||
*/
|
||||
@IBInspectable public var segmentBoundaryType: M13ProgressViewSegmentedRingSegmentBoundaryType = .Wedge {
|
||||
didSet {
|
||||
updateAngles()
|
||||
progressUpdate?()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Property Overrides
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The secondary color of the progress view.
|
||||
*/
|
||||
override public var secondaryColor: UIColor {
|
||||
didSet {
|
||||
indeterminateLayer.strokeColor = nil
|
||||
indeterminateLayer.fillColor = secondaryColor.CGColor
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Protected Variables
|
||||
//-------------------------------
|
||||
|
||||
// The calculated angles of the concentric rings
|
||||
internal var outerRingAngle :CGFloat = 0.1
|
||||
internal var innerRingAngle :CGFloat = 0.1
|
||||
internal var segmentSeparationInnerAngle :CGFloat = 0.1
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("numberOfSegments") {
|
||||
numberOfSegments = aDecoder.decodeIntegerForKey("numberOfSegments")
|
||||
}
|
||||
if aDecoder.containsValueForKey("segmentSeparationAngle") {
|
||||
segmentSeparationAngle = CGFloat(aDecoder.decodeDoubleForKey("segmentSeparationAngle"))
|
||||
}
|
||||
if aDecoder.containsValueForKey("segmentBoundaryType") {
|
||||
if let aSegmentBoundaryType = M13ProgressViewSegmentedRingSegmentBoundaryType(rawValue: aDecoder.decodeIntegerForKey("segmentBoundaryType")) {
|
||||
segmentBoundaryType = aSegmentBoundaryType
|
||||
}
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
internal override func sharedSetup() {
|
||||
super.sharedSetup()
|
||||
|
||||
// Set the defaults.
|
||||
self.clipsToBounds = false
|
||||
layer.backgroundColor = UIColor.clearColor().CGColor
|
||||
|
||||
// Set up the indeterminate layer
|
||||
indeterminateLayer.strokeColor = nil
|
||||
indeterminateLayer.fillColor = secondaryColor.CGColor
|
||||
|
||||
// Set up the progress layer
|
||||
progressLayer.strokeColor = nil
|
||||
progressLayer.fillColor = tintColor.CGColor
|
||||
|
||||
adjustProgressRingWidth()
|
||||
|
||||
// Set the progress animation.
|
||||
weak var weakSelf: M13ProgressSegmentedRing? = self
|
||||
progressUpdate = {() -> Void in
|
||||
|
||||
if let retainedSelf = weakSelf {
|
||||
|
||||
// Draw background
|
||||
retainedSelf.drawSegmentedBackground()
|
||||
|
||||
// Draw progress ring
|
||||
retainedSelf.drawSegmentedProgress()
|
||||
|
||||
// Draw percentage
|
||||
if retainedSelf.percentage && retainedSelf.state == .Normal {
|
||||
retainedSelf.drawPercentage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the indeterminate animation.
|
||||
indeterminateUpdate = {(frameDuration: CFTimeInterval) -> Void in
|
||||
|
||||
if let retainedSelf = weakSelf {
|
||||
|
||||
retainedSelf.hidePercentage()
|
||||
|
||||
// Create parameters to draw progress
|
||||
let startAngle = CGFloat(retainedSelf.indeterminateAnimationAngle)
|
||||
|
||||
let deltaAngle = CGFloat(frameDuration * M_PI)
|
||||
if retainedSelf.progressDirection == .CounterClockwise {
|
||||
// CounterClockwise
|
||||
retainedSelf.indeterminateAnimationAngle -= deltaAngle
|
||||
} else {
|
||||
// Clockwise
|
||||
retainedSelf.indeterminateAnimationAngle += deltaAngle
|
||||
}
|
||||
|
||||
// Draw animated background
|
||||
retainedSelf.drawSegmentedIndeterminate(startAngle, segmentsToDraw: retainedSelf.numberOfSegments)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeInteger(numberOfSegments, forKey: "numberOfSegments")
|
||||
aCoder.encodeDouble(Double(segmentSeparationAngle), forKey: "segmentSeparationAngle")
|
||||
aCoder.encodeInteger(segmentBoundaryType.rawValue, forKey: "segmentBoundaryType")
|
||||
super.encodeWithCoder(aCoder)
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
public override func setState(state: M13ProgressViewState, animated: Bool) {
|
||||
super.setState(state, animated: animated)
|
||||
|
||||
// Remove strokeColor animations and assignments that were added during super.setState()
|
||||
progressLayer.removeAnimationForKey("strokeColor")
|
||||
progressLayer.strokeColor = nil
|
||||
indeterminateLayer.removeAnimationForKey("strokeColor")
|
||||
indeterminateLayer.strokeColor = nil
|
||||
|
||||
// Select colors based on state
|
||||
var toColor1: UIColor = tintColor
|
||||
var toColor2: UIColor = secondaryColor
|
||||
switch state {
|
||||
case .Normal:
|
||||
break
|
||||
case .Success:
|
||||
toColor1 = successColor
|
||||
if indeterminate {
|
||||
toColor2 = successColor
|
||||
}
|
||||
break
|
||||
case .Failure:
|
||||
toColor1 = failureColor
|
||||
if indeterminate {
|
||||
toColor2 = failureColor
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if !animated {
|
||||
progressLayer.fillColor = toColor1.CGColor
|
||||
indeterminateLayer.fillColor = toColor2.CGColor
|
||||
} else {
|
||||
let colorAnimation1: CABasicAnimation = CABasicAnimation(keyPath: "fillColor")
|
||||
colorAnimation1.fromValue = progressLayer.backgroundColor!
|
||||
colorAnimation1.fillMode = kCAFillModeForwards
|
||||
colorAnimation1.removedOnCompletion = false
|
||||
colorAnimation1.duration = animationDuration
|
||||
|
||||
let colorAnimation2: CABasicAnimation = CABasicAnimation(keyPath: "fillColor")
|
||||
colorAnimation2.fromValue = indeterminateLayer.backgroundColor!
|
||||
colorAnimation2.fillMode = kCAFillModeForwards
|
||||
colorAnimation2.removedOnCompletion = false
|
||||
colorAnimation2.duration = animationDuration
|
||||
|
||||
colorAnimation1.toValue = toColor1.CGColor
|
||||
progressLayer.addAnimation(colorAnimation1, forKey: "fillColor")
|
||||
progressLayer.fillColor = toColor1.CGColor
|
||||
|
||||
colorAnimation2.toValue = toColor2.CGColor
|
||||
indeterminateLayer.addAnimation(colorAnimation2, forKey: "fillColor")
|
||||
indeterminateLayer.fillColor = toColor2.CGColor
|
||||
}
|
||||
|
||||
setNeedsLayout()
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout
|
||||
//-------------------------------
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
updateAngles()
|
||||
|
||||
// Update progress frame
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
internal func updateAngles() {
|
||||
// Calculate the outer ring angle for the progress segment.
|
||||
outerRingAngle = CGFloat(2.0 * M_PI) / CGFloat(numberOfSegments) - segmentSeparationAngle
|
||||
// Calculate the angle gap for the inner ring
|
||||
let radius = maxRadius()
|
||||
segmentSeparationInnerAngle = 2.0 * asin((radius * sin(segmentSeparationAngle / 2.0)) / (radius - CGFloat(progressRingWidth)))
|
||||
// Calculate the inner ring angle for the progress segment.
|
||||
innerRingAngle = CGFloat(2.0 * M_PI) / CGFloat(numberOfSegments) - segmentSeparationInnerAngle
|
||||
}
|
||||
|
||||
public func numberOfFullSegments() -> Int
|
||||
{
|
||||
return Int(floor(progress * CGFloat(numberOfSegments)))
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Draw Functions
|
||||
//-------------------------------
|
||||
|
||||
public func drawSegmentedIndeterminate(startAngle: CGFloat, segmentsToDraw: Int)
|
||||
{
|
||||
// Create parameters to draw background
|
||||
// The background segments are drawn counterclockwise, start with the outer ring, add an arc counterclockwise. Then add the coresponding arc for the inner ring clockwise. Then close the path. The line connecting the two arcs is not needed. From tests it seems to be created automatically.
|
||||
var outerStartAngle = CGFloat(-M_PI_2) + startAngle
|
||||
// Skip half of a separation angle, since the first separation will be centered upward.
|
||||
outerStartAngle -= segmentSeparationAngle / 2.0
|
||||
// Calculate the inner start angle position
|
||||
var innerStartAngle = CGFloat(-M_PI_2) + startAngle
|
||||
innerStartAngle -= segmentSeparationInnerAngle / 2.0 + innerRingAngle
|
||||
|
||||
// Create the path ref that all the paths will be appended
|
||||
let pathListRef = CGPathCreateMutable()
|
||||
|
||||
// Create each segment
|
||||
let center = centerOfCircle()
|
||||
let radius = maxRadius()
|
||||
let radiusInner = radius - CGFloat(progressRingWidth)
|
||||
for (var i = 0; i < segmentsToDraw; ++i) {
|
||||
// Create the outer ring segment
|
||||
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: outerStartAngle, endAngle: (outerStartAngle - outerRingAngle), clockwise: false)
|
||||
// Create the inner ring segment
|
||||
if (segmentBoundaryType == .Wedge) {
|
||||
path.addArcWithCenter(center, radius: radiusInner, startAngle: (outerStartAngle - outerRingAngle), endAngle: outerStartAngle, clockwise: true)
|
||||
} else if (segmentBoundaryType == .Rectangle) {
|
||||
path.addArcWithCenter(center, radius: radiusInner, startAngle: innerStartAngle, endAngle: (innerStartAngle + innerRingAngle), clockwise: true)
|
||||
}
|
||||
|
||||
path.closePath()
|
||||
// Add the segment to the path ref
|
||||
CGPathAddPath(pathListRef, nil, path.CGPath)
|
||||
|
||||
// Setup for the next segment
|
||||
outerStartAngle -= outerRingAngle + segmentSeparationAngle
|
||||
innerStartAngle -= innerRingAngle + segmentSeparationInnerAngle
|
||||
}
|
||||
|
||||
// Set the path
|
||||
indeterminateLayer.path = pathListRef
|
||||
|
||||
indeterminateLayer.transform = getTransformation()
|
||||
}
|
||||
|
||||
public func drawSegmentedBackground()
|
||||
{
|
||||
let segmentsToDraw = numberOfSegments - numberOfFullSegments()
|
||||
drawSegmentedIndeterminate(0, segmentsToDraw: segmentsToDraw)
|
||||
}
|
||||
|
||||
public func drawSegmentedProgress()
|
||||
{
|
||||
// Create parameters to draw background
|
||||
// The progress segments are drawn clockwise, start with the outer ring, add an arc clockwise. Then add the coresponding arc for the inner ring counterclockwise. Then close the path. The line connecting the two arcs is not needed. From tests it seems to be created automatically.
|
||||
var outerStartAngle = CGFloat(-M_PI_2)
|
||||
// Skip half of a separation angle, since the first separation will be centered upward.
|
||||
outerStartAngle += segmentSeparationAngle / 2.0
|
||||
// Calculate the inner start angle position
|
||||
var innerStartAngle = CGFloat(-M_PI_2)
|
||||
innerStartAngle += segmentSeparationInnerAngle / 2.0 + innerRingAngle
|
||||
|
||||
// Create the path ref that all the paths will be appended
|
||||
let pathListRef = CGPathCreateMutable()
|
||||
|
||||
// Create each segment
|
||||
let center = centerOfCircle()
|
||||
let radius = maxRadius()
|
||||
let radiusInner = radius - CGFloat(progressRingWidth)
|
||||
let stopper = numberOfFullSegments()
|
||||
for (var i = 0; i < stopper; ++i) {
|
||||
// Create the outer ring segment
|
||||
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: outerStartAngle, endAngle: (outerStartAngle + outerRingAngle), clockwise: true)
|
||||
// Create the inner ring segment
|
||||
if (segmentBoundaryType == .Wedge) {
|
||||
path.addArcWithCenter(center, radius: radiusInner, startAngle: (outerStartAngle + outerRingAngle), endAngle: outerStartAngle, clockwise: false)
|
||||
} else if (segmentBoundaryType == .Rectangle) {
|
||||
path.addArcWithCenter(center, radius: radiusInner, startAngle: innerStartAngle, endAngle: (innerStartAngle - innerRingAngle), clockwise: false)
|
||||
}
|
||||
|
||||
path.closePath()
|
||||
// Add the segment to the path ref
|
||||
CGPathAddPath(pathListRef, nil, path.CGPath)
|
||||
|
||||
// Setup for the next segment
|
||||
outerStartAngle += outerRingAngle + segmentSeparationAngle
|
||||
innerStartAngle += innerRingAngle + segmentSeparationInnerAngle
|
||||
}
|
||||
|
||||
// Set the path
|
||||
progressLayer.path = pathListRef
|
||||
|
||||
progressLayer.transform = getTransformation()
|
||||
}
|
||||
|
||||
public func getTransformation() -> CATransform3D
|
||||
{
|
||||
if progressDirection == .CounterClockwise {
|
||||
let rotation = CATransform3DMakeRotation(CGFloat(M_PI), 0.0, 1.0, 0.0)
|
||||
let x = self.bounds.size.width
|
||||
let translation = CATransform3DMakeTranslation(x, 0, 0)
|
||||
return CATransform3DConcat(rotation, translation)
|
||||
}
|
||||
|
||||
return CATransform3DIdentity
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Other
|
||||
//-------------------------------
|
||||
|
||||
public override func tintColorDidChange() {
|
||||
super.tintColorDidChange()
|
||||
progressLayer.fillColor = tintColor.CGColor
|
||||
progressLayer.strokeColor = nil
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
//
|
||||
// M13ProgressView.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
/*
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible states a progress view can be in.
|
||||
|
||||
- None: The default state of a progress bar.
|
||||
- Success: The state that shows an action completed successfully.
|
||||
- Failure: The state that shows an action failed to complete.
|
||||
*/
|
||||
public enum M13ProgressViewState: Int, RawRepresentable {
|
||||
/// The default state of a progress bar.
|
||||
case Normal
|
||||
/// The state that shows an action completed successfully.
|
||||
case Success
|
||||
/// The state that shows an action failed to complete.
|
||||
case Failure
|
||||
}
|
||||
|
||||
/**
|
||||
A standardized base upon which to build progress views.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressView: UIView {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Appearance
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The secondary color of the progress view.
|
||||
*/
|
||||
@IBInspectable public var secondaryColor: UIColor = UIColor.lightGrayColor()
|
||||
|
||||
/**
|
||||
The primary color when the progress view is in the success state.
|
||||
*/
|
||||
@IBInspectable public var successColor: UIColor = UIColor(red: 63.0/255.0, green: 226.0/255.0, blue: 80.0/255.0, alpha: 1.0)
|
||||
|
||||
/**
|
||||
The primary color when the progress view is in the failure state.
|
||||
*/
|
||||
@IBInspectable public var failureColor: UIColor = UIColor(red: 249.0/255.0, green: 37.0/255.0, blue: 0.0, alpha: 1.0)
|
||||
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Wether or not the progress view is in an indeterminate state.
|
||||
*/
|
||||
@IBInspectable public var indeterminate: Bool = false {
|
||||
didSet {
|
||||
if indeterminate && indeterminateDisplayLink == nil {
|
||||
// Create the display link
|
||||
indeterminateDisplayLink = CADisplayLink(target: self, selector: "animateIndeterminate:")
|
||||
indeterminateDisplayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
} else if !indeterminate && indeterminateDisplayLink != nil {
|
||||
// Remove the display link as the animation is not needed anymore.
|
||||
indeterminateDisplayLink?.invalidate()
|
||||
indeterminateDisplayLink = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The duration of the animations performed by the progress view in seconds.
|
||||
*/
|
||||
@IBInspectable public var animationDuration: NSTimeInterval = 0.3
|
||||
|
||||
/**
|
||||
The duration of the indeterminate animation loop in seconds.
|
||||
*/
|
||||
@IBInspectable public var indeterminateAnimationDuration: NSTimeInterval = 2.0
|
||||
|
||||
/**
|
||||
The progress displayed by the progress view.
|
||||
*/
|
||||
@IBInspectable public private(set) var progress: CGFloat = 0.0
|
||||
|
||||
/**
|
||||
The current state of the progress view
|
||||
*/
|
||||
@IBInspectable public private(set) var state: M13ProgressViewState = M13ProgressViewState.Normal
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Animation
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The progress at the beginning of the animation.
|
||||
*/
|
||||
private var progressFromValue: CGFloat = 0.0
|
||||
|
||||
/**
|
||||
The progress at the end of the animation.
|
||||
*/
|
||||
private var progressToValue: CGFloat = 0.0
|
||||
|
||||
/**
|
||||
The start time of the animation.
|
||||
*/
|
||||
private var animationStartTime: CFTimeInterval?
|
||||
|
||||
/**
|
||||
The display link controlling progress animations.
|
||||
*/
|
||||
private var determinateDisplayLink: CADisplayLink?
|
||||
|
||||
/**
|
||||
The display link controlling indeterminate animations.
|
||||
*/
|
||||
private var indeterminateDisplayLink: CADisplayLink?
|
||||
|
||||
/**
|
||||
The block of code that updates the user interface when the progress is set, animated or not. The changes made should reflect the current value of the progress variable.
|
||||
|
||||
- note: If capturing variable that is linked to `self`, be sure to do a "weak self" conversion.
|
||||
*/
|
||||
internal var progressUpdate: (() -> Void)?
|
||||
|
||||
/**
|
||||
The block of code that update the user interface during the indeterminate state. This code is tied into a CADisplayLink that will run this code each frame.
|
||||
|
||||
- note: If capturing variable that is linked to `self`, be sure to do a "weak self" conversion.
|
||||
*/
|
||||
internal var indeterminateUpdate: ((frameDuration: CFTimeInterval) -> Void)?
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
public init() {
|
||||
super.init(frame: CGRectZero)
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
if aDecoder.containsValueForKey("indeterminate") {
|
||||
indeterminate = aDecoder.decodeBoolForKey("indeterminate")
|
||||
}
|
||||
if aDecoder.containsValueForKey("animationDuration") {
|
||||
animationDuration = aDecoder.decodeDoubleForKey("animationDuration")
|
||||
}
|
||||
if aDecoder.containsValueForKey("progress") {
|
||||
progress = CGFloat(aDecoder.decodeFloatForKey("progress"))
|
||||
}
|
||||
if aDecoder.containsValueForKey("state") {
|
||||
if let aState = M13ProgressViewState(rawValue: aDecoder.decodeIntegerForKey("state")) {
|
||||
state = aState
|
||||
}
|
||||
}
|
||||
if let color: UIColor = aDecoder.decodeObjectOfClass(UIColor.self, forKey: "secondaryColor") {
|
||||
secondaryColor = color
|
||||
}
|
||||
if let color: UIColor = aDecoder.decodeObjectOfClass(UIColor.self, forKey: "successColor") {
|
||||
successColor = color
|
||||
}
|
||||
if let color: UIColor = aDecoder.decodeObjectOfClass(UIColor.self, forKey: "failureColor") {
|
||||
failureColor = color
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
|
||||
public override func encodeWithCoder(aCoder: NSCoder) {
|
||||
aCoder.encodeObject(secondaryColor, forKey: "secondaryColor")
|
||||
aCoder.encodeObject(successColor, forKey: "successColor")
|
||||
aCoder.encodeObject(failureColor, forKey: "failureColor")
|
||||
aCoder.encodeBool(indeterminate, forKey: "indeterminate")
|
||||
aCoder.encodeDouble(animationDuration, forKey: "animationDuration")
|
||||
aCoder.encodeFloat(Float(progress), forKey: "progress")
|
||||
aCoder.encodeInteger(state.rawValue, forKey: "state")
|
||||
super.encodeWithCoder(aCoder)
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Set the progress displayed in the progress view.
|
||||
|
||||
- parameter progress: The progress to be displayed by the progress view.
|
||||
- parameter animated: Wether or not to animate the change.
|
||||
*/
|
||||
public func setProgress(progress: CGFloat, animated: Bool) {
|
||||
|
||||
if animated == false {
|
||||
// Remove the display link as the animation is not needed anymore.
|
||||
determinateDisplayLink?.invalidate()
|
||||
determinateDisplayLink = nil
|
||||
animationStartTime = nil
|
||||
// Update the progress
|
||||
self.progress = progress
|
||||
progressUpdate?()
|
||||
} else {
|
||||
// If the display link does not exist, create it.
|
||||
if determinateDisplayLink == nil {
|
||||
determinateDisplayLink = CADisplayLink(target: self, selector: "animateProgress:")
|
||||
determinateDisplayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
}
|
||||
|
||||
// Update the values for the animation.
|
||||
progressFromValue = self.progress
|
||||
progressToValue = progress > 1.0 ? 1.0 : progress
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the progress in sync with the `CADisplayLink`, such that any changes are animated.
|
||||
|
||||
- parameter displayLink: The display link that is asking to calculate changes before the next render cycle.
|
||||
*/
|
||||
internal func animateProgress(displayLink: CADisplayLink) {
|
||||
|
||||
// Set the animation start time on the first displayed frame. The timestamp will read 0.0 until the first frame.
|
||||
if animationStartTime == nil {
|
||||
animationStartTime = displayLink.timestamp
|
||||
return
|
||||
}
|
||||
|
||||
weak var weakSelf: M13ProgressView? = self
|
||||
dispatch_async(dispatch_get_main_queue()) { () -> Void in
|
||||
if let weakSelf = weakSelf {
|
||||
let dt: Double = (weakSelf.determinateDisplayLink!.timestamp - weakSelf.animationStartTime!) / weakSelf.animationDuration
|
||||
if dt >= 1.0 {
|
||||
// The animation is complete.
|
||||
// Order is important! Otherwise concurrency will cause errors, because setProgress: will detect an animation in progress and try to stop it by itself. Once over one, set to actual progress amount. Animation is over.
|
||||
weakSelf.determinateDisplayLink?.invalidate()
|
||||
weakSelf.determinateDisplayLink = nil
|
||||
weakSelf.setProgress(weakSelf.progressToValue, animated: false)
|
||||
} else {
|
||||
//Update the progress and the display
|
||||
weakSelf.progress = weakSelf.progressFromValue + (CGFloat(dt) * (weakSelf.progressToValue - weakSelf.progressFromValue))
|
||||
weakSelf.progressUpdate?()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the indeterminate animation in sync with the `CADisplayLink`, such that any changes are animated.
|
||||
|
||||
- parameter displayLink: The display link that is asking to calculate changes before the next render cycle.
|
||||
*/
|
||||
internal func animateIndeterminate(displayLink: CADisplayLink) {
|
||||
weak var weakSelf: M13ProgressView? = self
|
||||
dispatch_async(dispatch_get_main_queue()) { () -> Void in
|
||||
weakSelf?.indeterminateUpdate?(frameDuration: displayLink.duration)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Perform the given action.
|
||||
|
||||
- note: Not all progress views support all actions.
|
||||
- seealso: `M13ProgressViewState`
|
||||
|
||||
- parameter action: The action to perform.
|
||||
- parameter animated: Wether or not to animate the change.
|
||||
*/
|
||||
public func setState(state: M13ProgressViewState, animated: Bool) {
|
||||
self.state = state
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Layout and Drawing
|
||||
//-------------------------------
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
// Just update the progress in case it is not currently animating. The indeterminate animation will update on the next frame.
|
||||
progressUpdate?()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
New Progress Views
|
||||
==================
|
||||
|
||||
Gradient Progress Views
|
||||
-----------------------
|
||||
A gradient along the direction of progress.
|
||||
|
||||
- Option to show 100% of the gradient range, or cut off the gradient to only the visible progress percentage. (If that makes any sense.)
|
||||
- Add as a subclass of each progress view class?
|
||||
|
||||
Bordered Segmented Progress Views
|
||||
---------------------------------
|
||||
Bordered segmented progress views (Each segment has its own outline)
|
||||
|
||||
Size Based Segmented Progress Views
|
||||
-----------------------------------
|
||||
Size based segmented progress view that increases the size of the segments as progress increases.
|
||||
|
||||
Image Sequence
|
||||
--------------
|
||||
Maps progress information to images in an array.
|
||||
|
||||
- Accepts an array of UIImages for determinate, indeterminate, animating between determinate and indeterminate, success (and animating to/from), and failure (and animating to/from.)
|
||||
- Accepts gif file paths?
|
||||
- Accepts asset image sequence name?
|
||||
- Accepts an array of arrays of UIImages, such that each progress amount is also animated?
|
||||
|
||||
Custom Path Progress "Bar"
|
||||
------------------------
|
||||
Takes a custom path and animates the stroke of the path to denote progress.
|
||||
|
||||
- Possibly animate between paths for different states.
|
||||
|
||||
Liquid
|
||||
------
|
||||
Fills a shape with liquid
|
||||
|
||||
- Add dynamics based on device tilt?
|
||||
|
||||
Text
|
||||
----
|
||||
Animates text to show progress.
|
||||
|
||||
- Fill
|
||||
- Stroke
|
||||
- Size?
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Switch the primary color to a function that could change the primary color based on the percentage completed? By default it would just return the tint color.
|
||||
- Add more states like "warning", "error"
|
||||
@@ -1,37 +0,0 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "M13ProgressSuite"
|
||||
s.version = "2.0.0"
|
||||
s.summary = "A suite containing many tools to display progress information on iOS."
|
||||
|
||||
s.description = <<-DESC
|
||||
M13ProgressSuite includes many diffrent of styles of progress views: bar, ring, pie, etc. It also includes a HUD overlay and a UINavigationController with progress bar built in.
|
||||
DESC
|
||||
|
||||
s.homepage = "https://github.com/Marxon13/M13ProgressSuite"
|
||||
s.license = {:type => 'MIT',
|
||||
:text => <<-LICENSE
|
||||
Copyright (c) 2015 Brandon McQuilkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
LICENSE
|
||||
}
|
||||
|
||||
s.author = { "Brandon McQuilkin" => "brandon.mcquilkin@gmail.com" }
|
||||
|
||||
s.platform = :ios, '8.0'
|
||||
|
||||
s.source = { :git => "https://github.com/Marxon13/M13ProgressSuite.git", :tag => "v2.0.0"}
|
||||
|
||||
s.source_files = 'Classes/**/*'
|
||||
|
||||
s.frameworks = 'Foundation', 'UIKit', 'QuartzCore', 'CoreImage', 'Accelerate', 'CoreGraphics'
|
||||
|
||||
s.requires_arc = true
|
||||
end
|
||||
@@ -7,65 +7,27 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
EA9045701C0649AF006C692A /* M13HUDController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9045651C0649AF006C692A /* M13HUDController.swift */; };
|
||||
EA9045711C0649AF006C692A /* M13BorderedProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9045671C0649AF006C692A /* M13BorderedProgressBar.swift */; };
|
||||
EA9045721C0649AF006C692A /* M13ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9045681C0649AF006C692A /* M13ProgressBar.swift */; };
|
||||
EA9045731C0649AF006C692A /* M13ProgressCircular.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9045691C0649AF006C692A /* M13ProgressCircular.swift */; };
|
||||
EA9045741C0649AF006C692A /* M13ProgressFilteredImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA90456A1C0649AF006C692A /* M13ProgressFilteredImage.swift */; };
|
||||
EA9045751C0649AF006C692A /* M13ProgressImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA90456B1C0649AF006C692A /* M13ProgressImage.swift */; };
|
||||
EA9045761C0649AF006C692A /* M13ProgressPie.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA90456C1C0649AF006C692A /* M13ProgressPie.swift */; };
|
||||
EA9045771C0649AF006C692A /* M13ProgressRing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA90456D1C0649AF006C692A /* M13ProgressRing.swift */; };
|
||||
EA9045781C0649AF006C692A /* M13ProgressSegmentedRing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA90456E1C0649AF006C692A /* M13ProgressSegmentedRing.swift */; };
|
||||
EA9045791C0649AF006C692A /* M13ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA90456F1C0649AF006C692A /* M13ProgressView.swift */; };
|
||||
EA90457F1C065733006C692A /* Examples.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EA90457E1C065733006C692A /* Examples.storyboard */; };
|
||||
EABA2F6A1C08B25C006FA498 /* BorderedBarExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABA2F691C08B25C006FA498 /* BorderedBarExampleViewController.swift */; };
|
||||
EABA2F6C1C08B44C006FA498 /* RingExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABA2F6B1C08B44C006FA498 /* RingExampleViewController.swift */; };
|
||||
EABA2F6E1C08B9EE006FA498 /* SegmentedRingExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABA2F6D1C08B9EE006FA498 /* SegmentedRingExampleViewController.swift */; };
|
||||
EABA2F701C08BD02006FA498 /* PieExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABA2F6F1C08BD02006FA498 /* PieExampleViewController.swift */; };
|
||||
EABA2F721C09F651006FA498 /* GreyscaleImageExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABA2F711C09F651006FA498 /* GreyscaleImageExampleViewController.swift */; };
|
||||
EABA2F741C09FA1E006FA498 /* FilteredImageExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABA2F731C09FA1E006FA498 /* FilteredImageExampleViewController.swift */; };
|
||||
EADD11311C06A2F4001862B2 /* BaseExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADD11301C06A2F4001862B2 /* BaseExampleViewController.swift */; };
|
||||
EADD11331C06AEFA001862B2 /* BarExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADD11321C06AEFA001862B2 /* BarExampleViewController.swift */; };
|
||||
EAF117331C0647D0003616CD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF117321C0647D0003616CD /* AppDelegate.swift */; };
|
||||
EAF117351C0647D0003616CD /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF117341C0647D0003616CD /* MasterViewController.swift */; };
|
||||
EAF117371C0647D0003616CD /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF117361C0647D0003616CD /* DetailViewController.swift */; };
|
||||
EAF1173A1C0647D0003616CD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAF117381C0647D0003616CD /* Main.storyboard */; };
|
||||
EAF1173C1C0647D0003616CD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAF1173B1C0647D0003616CD /* Assets.xcassets */; };
|
||||
EAF1173F1C0647D0003616CD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAF1173D1C0647D0003616CD /* LaunchScreen.storyboard */; };
|
||||
43E4A70D1D58E77100030A4F /* M13ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E4A70C1D58E77100030A4F /* M13ProgressBar.swift */; };
|
||||
43E4A70F1D58ECAE00030A4F /* M13ProgressViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E4A70E1D58ECAE00030A4F /* M13ProgressViewBase.swift */; };
|
||||
EAC2CA591D578B5D0007D30D /* M13ProgressSuite.h in Headers */ = {isa = PBXBuildFile; fileRef = EAC2CA571D578B5D0007D30D /* M13ProgressSuite.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
EAC2CA611D578BFA0007D30D /* M13ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC2CA601D578BFA0007D30D /* M13ProgressView.swift */; };
|
||||
EAC2CA631D578C330007D30D /* M13ProgressState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC2CA621D578C330007D30D /* M13ProgressState.swift */; };
|
||||
EAC2CA661D57BA140007D30D /* M13ProgressType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC2CA651D57BA140007D30D /* M13ProgressType.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
EA9045651C0649AF006C692A /* M13HUDController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13HUDController.swift; sourceTree = "<group>"; };
|
||||
EA9045671C0649AF006C692A /* M13BorderedProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13BorderedProgressBar.swift; sourceTree = "<group>"; };
|
||||
EA9045681C0649AF006C692A /* M13ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressBar.swift; sourceTree = "<group>"; };
|
||||
EA9045691C0649AF006C692A /* M13ProgressCircular.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressCircular.swift; sourceTree = "<group>"; };
|
||||
EA90456A1C0649AF006C692A /* M13ProgressFilteredImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressFilteredImage.swift; sourceTree = "<group>"; };
|
||||
EA90456B1C0649AF006C692A /* M13ProgressImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressImage.swift; sourceTree = "<group>"; };
|
||||
EA90456C1C0649AF006C692A /* M13ProgressPie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressPie.swift; sourceTree = "<group>"; };
|
||||
EA90456D1C0649AF006C692A /* M13ProgressRing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressRing.swift; sourceTree = "<group>"; };
|
||||
EA90456E1C0649AF006C692A /* M13ProgressSegmentedRing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressSegmentedRing.swift; sourceTree = "<group>"; };
|
||||
EA90456F1C0649AF006C692A /* M13ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M13ProgressView.swift; sourceTree = "<group>"; };
|
||||
EA90457E1C065733006C692A /* Examples.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Examples.storyboard; sourceTree = "<group>"; };
|
||||
EABA2F691C08B25C006FA498 /* BorderedBarExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BorderedBarExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EABA2F6B1C08B44C006FA498 /* RingExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RingExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EABA2F6D1C08B9EE006FA498 /* SegmentedRingExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedRingExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EABA2F6F1C08BD02006FA498 /* PieExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EABA2F711C09F651006FA498 /* GreyscaleImageExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GreyscaleImageExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EABA2F731C09FA1E006FA498 /* FilteredImageExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilteredImageExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EADD11301C06A2F4001862B2 /* BaseExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseExampleViewController.swift; path = Examples/BaseExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EADD11321C06AEFA001862B2 /* BarExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarExampleViewController.swift; sourceTree = "<group>"; };
|
||||
EAF1172F1C0647D0003616CD /* M13ProgressSuite.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = M13ProgressSuite.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EAF117321C0647D0003616CD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
EAF117341C0647D0003616CD /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = "<group>"; };
|
||||
EAF117361C0647D0003616CD /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
|
||||
EAF117391C0647D0003616CD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
EAF1173B1C0647D0003616CD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
EAF1173E1C0647D0003616CD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
EAF117401C0647D0003616CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
43E4A70C1D58E77100030A4F /* M13ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13ProgressBar.swift; path = Sources/M13ProgressBar.swift; sourceTree = "<group>"; };
|
||||
43E4A70E1D58ECAE00030A4F /* M13ProgressViewBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13ProgressViewBase.swift; path = Sources/M13ProgressViewBase.swift; sourceTree = "<group>"; };
|
||||
EAC2CA541D578B5D0007D30D /* M13ProgressSuite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = M13ProgressSuite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EAC2CA571D578B5D0007D30D /* M13ProgressSuite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = M13ProgressSuite.h; sourceTree = "<group>"; };
|
||||
EAC2CA581D578B5D0007D30D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
EAC2CA601D578BFA0007D30D /* M13ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13ProgressView.swift; path = Sources/M13ProgressView.swift; sourceTree = "<group>"; };
|
||||
EAC2CA621D578C330007D30D /* M13ProgressState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13ProgressState.swift; path = Sources/M13ProgressState.swift; sourceTree = "<group>"; };
|
||||
EAC2CA651D57BA140007D30D /* M13ProgressType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13ProgressType.swift; path = Sources/M13ProgressType.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
EAF1172C1C0647D0003616CD /* Frameworks */ = {
|
||||
EAC2CA501D578B5D0007D30D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -75,129 +37,82 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
EA9045621C06499A006C692A /* Example App */ = {
|
||||
43E4A70B1D58E75300030A4F /* Progress Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA90457A1C0649C5006C692A /* Example Views */,
|
||||
EAF117321C0647D0003616CD /* AppDelegate.swift */,
|
||||
EAF117341C0647D0003616CD /* MasterViewController.swift */,
|
||||
EAF117361C0647D0003616CD /* DetailViewController.swift */,
|
||||
EAF117381C0647D0003616CD /* Main.storyboard */,
|
||||
EA90457E1C065733006C692A /* Examples.storyboard */,
|
||||
EAF1173B1C0647D0003616CD /* Assets.xcassets */,
|
||||
EAF1173D1C0647D0003616CD /* LaunchScreen.storyboard */,
|
||||
EAF117401C0647D0003616CD /* Info.plist */,
|
||||
43E4A70C1D58E77100030A4F /* M13ProgressBar.swift */,
|
||||
);
|
||||
name = "Example App";
|
||||
name = "Progress Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA9045631C0649AF006C692A /* Classes */ = {
|
||||
EAC2CA4A1D578B5D0007D30D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA9045641C0649AF006C692A /* HUD */,
|
||||
EA9045661C0649AF006C692A /* Progress Views */,
|
||||
);
|
||||
path = Classes;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
EA9045641C0649AF006C692A /* HUD */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA9045651C0649AF006C692A /* M13HUDController.swift */,
|
||||
);
|
||||
path = HUD;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA9045661C0649AF006C692A /* Progress Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA90456F1C0649AF006C692A /* M13ProgressView.swift */,
|
||||
EA90457B1C0651FD006C692A /* Bar */,
|
||||
EA90457C1C065232006C692A /* Circular */,
|
||||
EA90457D1C065258006C692A /* Image */,
|
||||
);
|
||||
path = "Progress Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA90457A1C0649C5006C692A /* Example Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EADD11301C06A2F4001862B2 /* BaseExampleViewController.swift */,
|
||||
EADD11321C06AEFA001862B2 /* BarExampleViewController.swift */,
|
||||
EABA2F691C08B25C006FA498 /* BorderedBarExampleViewController.swift */,
|
||||
EABA2F6B1C08B44C006FA498 /* RingExampleViewController.swift */,
|
||||
EABA2F6D1C08B9EE006FA498 /* SegmentedRingExampleViewController.swift */,
|
||||
EABA2F6F1C08BD02006FA498 /* PieExampleViewController.swift */,
|
||||
EABA2F711C09F651006FA498 /* GreyscaleImageExampleViewController.swift */,
|
||||
EABA2F731C09FA1E006FA498 /* FilteredImageExampleViewController.swift */,
|
||||
);
|
||||
name = "Example Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA90457B1C0651FD006C692A /* Bar */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA9045681C0649AF006C692A /* M13ProgressBar.swift */,
|
||||
EA9045671C0649AF006C692A /* M13BorderedProgressBar.swift */,
|
||||
);
|
||||
name = Bar;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA90457C1C065232006C692A /* Circular */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA9045691C0649AF006C692A /* M13ProgressCircular.swift */,
|
||||
EA90456C1C0649AF006C692A /* M13ProgressPie.swift */,
|
||||
EA90456D1C0649AF006C692A /* M13ProgressRing.swift */,
|
||||
EA90456E1C0649AF006C692A /* M13ProgressSegmentedRing.swift */,
|
||||
);
|
||||
name = Circular;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA90457D1C065258006C692A /* Image */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA90456A1C0649AF006C692A /* M13ProgressFilteredImage.swift */,
|
||||
EA90456B1C0649AF006C692A /* M13ProgressImage.swift */,
|
||||
);
|
||||
name = Image;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAF117261C0647D0003616CD = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAF117311C0647D0003616CD /* M13ProgressSuite */,
|
||||
EAF117301C0647D0003616CD /* Products */,
|
||||
EAC2CA5F1D578BE70007D30D /* Sources */,
|
||||
EAC2CA561D578B5D0007D30D /* M13ProgressSuite */,
|
||||
EAC2CA551D578B5D0007D30D /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAF117301C0647D0003616CD /* Products */ = {
|
||||
EAC2CA551D578B5D0007D30D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAF1172F1C0647D0003616CD /* M13ProgressSuite.app */,
|
||||
EAC2CA541D578B5D0007D30D /* M13ProgressSuite.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAF117311C0647D0003616CD /* M13ProgressSuite */ = {
|
||||
EAC2CA561D578B5D0007D30D /* M13ProgressSuite */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA9045631C0649AF006C692A /* Classes */,
|
||||
EA9045621C06499A006C692A /* Example App */,
|
||||
EAC2CA571D578B5D0007D30D /* M13ProgressSuite.h */,
|
||||
EAC2CA581D578B5D0007D30D /* Info.plist */,
|
||||
);
|
||||
path = M13ProgressSuite;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAC2CA5F1D578BE70007D30D /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAC2CA641D57B9E30007D30D /* Base */,
|
||||
43E4A70B1D58E75300030A4F /* Progress Views */,
|
||||
);
|
||||
name = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAC2CA641D57B9E30007D30D /* Base */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAC2CA601D578BFA0007D30D /* M13ProgressView.swift */,
|
||||
EAC2CA621D578C330007D30D /* M13ProgressState.swift */,
|
||||
EAC2CA651D57BA140007D30D /* M13ProgressType.swift */,
|
||||
43E4A70E1D58ECAE00030A4F /* M13ProgressViewBase.swift */,
|
||||
);
|
||||
name = Base;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
EAC2CA511D578B5D0007D30D /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EAC2CA591D578B5D0007D30D /* M13ProgressSuite.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
EAF1172E1C0647D0003616CD /* M13ProgressSuite */ = {
|
||||
EAC2CA531D578B5D0007D30D /* M13ProgressSuite */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = EAF117431C0647D0003616CD /* Build configuration list for PBXNativeTarget "M13ProgressSuite" */;
|
||||
buildConfigurationList = EAC2CA5C1D578B5D0007D30D /* Build configuration list for PBXNativeTarget "M13ProgressSuite" */;
|
||||
buildPhases = (
|
||||
EAF1172B1C0647D0003616CD /* Sources */,
|
||||
EAF1172C1C0647D0003616CD /* Frameworks */,
|
||||
EAF1172D1C0647D0003616CD /* Resources */,
|
||||
EAC2CA4F1D578B5D0007D30D /* Sources */,
|
||||
EAC2CA501D578B5D0007D30D /* Frameworks */,
|
||||
EAC2CA511D578B5D0007D30D /* Headers */,
|
||||
EAC2CA521D578B5D0007D30D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -205,112 +120,74 @@
|
||||
);
|
||||
name = M13ProgressSuite;
|
||||
productName = M13ProgressSuite;
|
||||
productReference = EAF1172F1C0647D0003616CD /* M13ProgressSuite.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
productReference = EAC2CA541D578B5D0007D30D /* M13ProgressSuite.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
EAF117271C0647D0003616CD /* Project object */ = {
|
||||
EAC2CA4B1D578B5D0007D30D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0710;
|
||||
LastUpgradeCheck = 0710;
|
||||
ORGANIZATIONNAME = Marxon13;
|
||||
LastUpgradeCheck = 0800;
|
||||
ORGANIZATIONNAME = "Brandon McQuilkin";
|
||||
TargetAttributes = {
|
||||
EAF1172E1C0647D0003616CD = {
|
||||
CreatedOnToolsVersion = 7.1.1;
|
||||
EAC2CA531D578B5D0007D30D = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
DevelopmentTeam = 3RCGQ2RRJJ;
|
||||
LastSwiftMigration = 0800;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = EAF1172A1C0647D0003616CD /* Build configuration list for PBXProject "M13ProgressSuite" */;
|
||||
buildConfigurationList = EAC2CA4E1D578B5D0007D30D /* Build configuration list for PBXProject "M13ProgressSuite" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = EAF117261C0647D0003616CD;
|
||||
productRefGroup = EAF117301C0647D0003616CD /* Products */;
|
||||
mainGroup = EAC2CA4A1D578B5D0007D30D;
|
||||
productRefGroup = EAC2CA551D578B5D0007D30D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
EAF1172E1C0647D0003616CD /* M13ProgressSuite */,
|
||||
EAC2CA531D578B5D0007D30D /* M13ProgressSuite */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
EAF1172D1C0647D0003616CD /* Resources */ = {
|
||||
EAC2CA521D578B5D0007D30D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EAF1173F1C0647D0003616CD /* LaunchScreen.storyboard in Resources */,
|
||||
EA90457F1C065733006C692A /* Examples.storyboard in Resources */,
|
||||
EAF1173C1C0647D0003616CD /* Assets.xcassets in Resources */,
|
||||
EAF1173A1C0647D0003616CD /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
EAF1172B1C0647D0003616CD /* Sources */ = {
|
||||
EAC2CA4F1D578B5D0007D30D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EABA2F701C08BD02006FA498 /* PieExampleViewController.swift in Sources */,
|
||||
EABA2F721C09F651006FA498 /* GreyscaleImageExampleViewController.swift in Sources */,
|
||||
EA9045721C0649AF006C692A /* M13ProgressBar.swift in Sources */,
|
||||
EA9045741C0649AF006C692A /* M13ProgressFilteredImage.swift in Sources */,
|
||||
EAF117371C0647D0003616CD /* DetailViewController.swift in Sources */,
|
||||
EA9045771C0649AF006C692A /* M13ProgressRing.swift in Sources */,
|
||||
EA9045731C0649AF006C692A /* M13ProgressCircular.swift in Sources */,
|
||||
EA9045711C0649AF006C692A /* M13BorderedProgressBar.swift in Sources */,
|
||||
EA9045751C0649AF006C692A /* M13ProgressImage.swift in Sources */,
|
||||
EA9045791C0649AF006C692A /* M13ProgressView.swift in Sources */,
|
||||
EABA2F6E1C08B9EE006FA498 /* SegmentedRingExampleViewController.swift in Sources */,
|
||||
EABA2F6A1C08B25C006FA498 /* BorderedBarExampleViewController.swift in Sources */,
|
||||
EAF117351C0647D0003616CD /* MasterViewController.swift in Sources */,
|
||||
EA9045761C0649AF006C692A /* M13ProgressPie.swift in Sources */,
|
||||
EAF117331C0647D0003616CD /* AppDelegate.swift in Sources */,
|
||||
EA9045701C0649AF006C692A /* M13HUDController.swift in Sources */,
|
||||
EADD11331C06AEFA001862B2 /* BarExampleViewController.swift in Sources */,
|
||||
EADD11311C06A2F4001862B2 /* BaseExampleViewController.swift in Sources */,
|
||||
EABA2F6C1C08B44C006FA498 /* RingExampleViewController.swift in Sources */,
|
||||
EABA2F741C09FA1E006FA498 /* FilteredImageExampleViewController.swift in Sources */,
|
||||
EA9045781C0649AF006C692A /* M13ProgressSegmentedRing.swift in Sources */,
|
||||
EAC2CA631D578C330007D30D /* M13ProgressState.swift in Sources */,
|
||||
EAC2CA661D57BA140007D30D /* M13ProgressType.swift in Sources */,
|
||||
43E4A70F1D58ECAE00030A4F /* M13ProgressViewBase.swift in Sources */,
|
||||
43E4A70D1D58E77100030A4F /* M13ProgressBar.swift in Sources */,
|
||||
EAC2CA611D578BFA0007D30D /* M13ProgressView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
EAF117381C0647D0003616CD /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
EAF117391C0647D0003616CD /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAF1173D1C0647D0003616CD /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
EAF1173E1C0647D0003616CD /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
EAF117411C0647D0003616CD /* Debug */ = {
|
||||
EAC2CA5A1D578B5D0007D30D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -318,14 +195,18 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -343,19 +224,23 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.1;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
EAF117421C0647D0003616CD /* Release */ = {
|
||||
EAC2CA5B1D578B5D0007D30D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -363,14 +248,18 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -382,62 +271,80 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.1;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
EAF117441C0647D0003616CD /* Debug */ = {
|
||||
EAC2CA5D1D578B5D0007D30D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 3RCGQ2RRJJ;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = M13ProgressSuite/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.marxon13.M13ProgressSuite;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.BrandonMcQuilkin.M13ProgressSuite;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
EAF117451C0647D0003616CD /* Release */ = {
|
||||
EAC2CA5E1D578B5D0007D30D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 3RCGQ2RRJJ;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = M13ProgressSuite/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.marxon13.M13ProgressSuite;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.BrandonMcQuilkin.M13ProgressSuite;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
EAF1172A1C0647D0003616CD /* Build configuration list for PBXProject "M13ProgressSuite" */ = {
|
||||
EAC2CA4E1D578B5D0007D30D /* Build configuration list for PBXProject "M13ProgressSuite" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
EAF117411C0647D0003616CD /* Debug */,
|
||||
EAF117421C0647D0003616CD /* Release */,
|
||||
EAC2CA5A1D578B5D0007D30D /* Debug */,
|
||||
EAC2CA5B1D578B5D0007D30D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
EAF117431C0647D0003616CD /* Build configuration list for PBXNativeTarget "M13ProgressSuite" */ = {
|
||||
EAC2CA5C1D578B5D0007D30D /* Build configuration list for PBXNativeTarget "M13ProgressSuite" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
EAF117441C0647D0003616CD /* Debug */,
|
||||
EAF117451C0647D0003616CD /* Release */,
|
||||
EAC2CA5D1D578B5D0007D30D /* Debug */,
|
||||
EAC2CA5E1D578B5D0007D30D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = EAF117271C0647D0003616CD /* Project object */;
|
||||
rootObject = EAC2CA4B1D578B5D0007D30D /* Project object */;
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/25/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
let splitViewController = self.window!.rootViewController as! UISplitViewController
|
||||
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
|
||||
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
|
||||
splitViewController.delegate = self
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(application: UIApplication) {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
// MARK: - Split view
|
||||
|
||||
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool {
|
||||
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
|
||||
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
|
||||
if topAsDetailController.detailViewController == nil {
|
||||
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Striped_apple_logo.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Striped_apple_logo-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Striped_apple_logo-2.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB |
@@ -1,67 +0,0 @@
|
||||
//
|
||||
// BarExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/25/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class BarExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The vertical progress bar.
|
||||
@IBOutlet var verticalProgressBar: M13ProgressBar?
|
||||
|
||||
/// The horizontal progress bar.
|
||||
@IBOutlet var horizontalProgressBar: M13ProgressBar?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let verticalProgressBar = verticalProgressBar, horizontalProgressBar = horizontalProgressBar {
|
||||
return [verticalProgressBar, horizontalProgressBar]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
verticalProgressBar?.progressDirection = .BottomToTop
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Updates the corner radius of the progress views.
|
||||
- parameter sender: The slider that updated its value.
|
||||
*/
|
||||
@IBAction func updateCornerRadius(sender: UISlider) {
|
||||
horizontalProgressBar?.cornerRadius = CGFloat(sender.value)
|
||||
verticalProgressBar?.cornerRadius = CGFloat(sender.value)
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the direction of the progress views.
|
||||
*/
|
||||
@IBAction func updateProgressDirection(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
horizontalProgressBar?.progressDirection = .LeadingToTrailing
|
||||
verticalProgressBar?.progressDirection = .BottomToTop
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
horizontalProgressBar?.progressDirection = .TrailingToLeading
|
||||
verticalProgressBar?.progressDirection = .TopToBottom
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,160 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="H1p-Uh-vWS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Master-->
|
||||
<scene sceneID="pY4-Hu-kfo">
|
||||
<objects>
|
||||
<navigationController title="Master" id="RMx-3f-FxP" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="Pmd-2v-anx">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="7bK-jq-Zjz" kind="relationship" relationship="rootViewController" id="tsl-Nk-0bq"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="8fS-aE-onr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-38" y="-630"/>
|
||||
</scene>
|
||||
<!--Detail-->
|
||||
<scene sceneID="yUG-lL-AsK">
|
||||
<objects>
|
||||
<viewController title="Detail" id="JEX-9P-axG" customClass="DetailViewController" customModule="M13ProgressSuite" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="SYR-Wa-9uf"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="GAO-Cl-Wes"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="svH-Pt-448">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Select an Example" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q3I-gn-7hF">
|
||||
<rect key="frame" x="193" y="284" width="214.5" height="32.5"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" delaysContentTouches="NO" canCancelContentTouches="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vrn-fU-KbN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<animations/>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Vrn-fU-KbN" firstAttribute="leading" secondItem="svH-Pt-448" secondAttribute="leadingMargin" constant="-20" id="5MK-tF-sRx"/>
|
||||
<constraint firstItem="Q3I-gn-7hF" firstAttribute="centerX" secondItem="svH-Pt-448" secondAttribute="centerX" id="E89-pa-1Nj"/>
|
||||
<constraint firstItem="Vrn-fU-KbN" firstAttribute="leading" secondItem="svH-Pt-448" secondAttribute="leading" id="Hjb-Fk-zsC"/>
|
||||
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="Q3I-gn-7hF" secondAttribute="trailing" constant="20" id="M5W-qA-gpV"/>
|
||||
<constraint firstItem="GAO-Cl-Wes" firstAttribute="top" secondItem="Vrn-fU-KbN" secondAttribute="bottom" id="P0m-Ed-ymG"/>
|
||||
<constraint firstItem="Q3I-gn-7hF" firstAttribute="centerY" secondItem="svH-Pt-448" secondAttribute="centerY" id="fqT-YV-TDr"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Vrn-fU-KbN" secondAttribute="trailing" id="gX0-Wk-Z8b"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="Vrn-fU-KbN" secondAttribute="trailing" constant="-20" id="p2i-kz-b78"/>
|
||||
<constraint firstItem="Q3I-gn-7hF" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="svH-Pt-448" secondAttribute="leadingMargin" constant="20" id="sdY-8C-5jS"/>
|
||||
<constraint firstItem="Vrn-fU-KbN" firstAttribute="top" secondItem="svH-Pt-448" secondAttribute="topMargin" id="vqs-tW-Yle"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="5MK-tF-sRx"/>
|
||||
<exclude reference="p2i-kz-b78"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</view>
|
||||
<toolbarItems/>
|
||||
<navigationItem key="navigationItem" title="Example" id="mOI-FS-AaM"/>
|
||||
<connections>
|
||||
<outlet property="progressContentScrollView" destination="Vrn-fU-KbN" id="NIa-NU-bti"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="709" y="129"/>
|
||||
</scene>
|
||||
<!--Split View Controller-->
|
||||
<scene sceneID="Nki-YV-4Qg">
|
||||
<objects>
|
||||
<splitViewController id="H1p-Uh-vWS" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<connections>
|
||||
<segue destination="RMx-3f-FxP" kind="relationship" relationship="masterViewController" id="BlO-5A-QYV"/>
|
||||
<segue destination="vC3-pB-5Vb" kind="relationship" relationship="detailViewController" id="Tll-UG-LXB"/>
|
||||
</connections>
|
||||
</splitViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="cZU-Oi-B1e" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-856" y="-330"/>
|
||||
</scene>
|
||||
<!--Master-->
|
||||
<scene sceneID="smW-Zh-WAh">
|
||||
<objects>
|
||||
<tableViewController title="Master" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterViewController" customModule="M13ProgressSuite" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="r7i-6Z-zg0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="Cell" textLabel="Arm-wq-HPj" style="IBUITableViewCellStyleDefault" id="WCw-Qf-5nD">
|
||||
<rect key="frame" x="0.0" y="113.5" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WCw-Qf-5nD" id="37f-cq-3Eg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Arm-wq-HPj">
|
||||
<rect key="frame" x="15" y="0.0" width="570" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showDetail" id="6S0-TO-JiA"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<sections/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="7bK-jq-Zjz" id="Gho-Na-rnu"/>
|
||||
<outlet property="delegate" destination="7bK-jq-Zjz" id="RA6-mI-bju"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Examples" id="Zdf-7t-Un8"/>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="709" y="-630"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="r7l-gg-dq7">
|
||||
<objects>
|
||||
<navigationController id="vC3-pB-5Vb" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="DjV-YW-jjY">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="JEX-9P-axG" kind="relationship" relationship="rootViewController" id="GKi-kA-LjT"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="SLD-UC-DBI" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-45" y="129"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="6S0-TO-JiA"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// BorderedBarExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/27/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class BorderedBarExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The vertical progress bar.
|
||||
@IBOutlet var verticalProgressBar: M13BorderedProgressBar?
|
||||
|
||||
/// The horizontal progress bar.
|
||||
@IBOutlet var horizontalProgressBar: M13BorderedProgressBar?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let verticalProgressBar = verticalProgressBar, horizontalProgressBar = horizontalProgressBar {
|
||||
return [verticalProgressBar, horizontalProgressBar]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
verticalProgressBar?.progressDirection = .BottomToTop
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Updates the corner radius of the progress views.
|
||||
- parameter sender: The slider that updated its value.
|
||||
*/
|
||||
@IBAction func updateCornerRadius(sender: UISlider) {
|
||||
horizontalProgressBar?.cornerRadius = CGFloat(sender.value)
|
||||
verticalProgressBar?.cornerRadius = CGFloat(sender.value)
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the direction of the progress views.
|
||||
- parameter sender: The segmented control that updated its value.
|
||||
*/
|
||||
@IBAction func updateProgressDirection(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
horizontalProgressBar?.progressDirection = .LeadingToTrailing
|
||||
verticalProgressBar?.progressDirection = .BottomToTop
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
horizontalProgressBar?.progressDirection = .TrailingToLeading
|
||||
verticalProgressBar?.progressDirection = .TopToBottom
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// DetailViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/25/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// The view controller that presents the progress examples.
|
||||
class DetailViewController: UIViewController {
|
||||
|
||||
//-----------------------------
|
||||
// MARK: - Properties
|
||||
//-----------------------------
|
||||
|
||||
/// The scroll view that will containt the progress view examples.
|
||||
@IBOutlet weak var progressContentScrollView: UIScrollView?
|
||||
|
||||
/// The view that is currently displayed in the content scroll view.
|
||||
var detailViewController: UIViewController? {
|
||||
willSet {
|
||||
detailViewController?.willMoveToParentViewController(nil)
|
||||
detailViewController?.view.removeFromSuperview()
|
||||
detailViewController?.removeFromParentViewController()
|
||||
}
|
||||
didSet {
|
||||
configureView()
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
// MARK: - Configuration
|
||||
//-----------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
self.configureView()
|
||||
}
|
||||
|
||||
/// Sets up the autolayout constraints for the content view.
|
||||
func configureView() {
|
||||
|
||||
// Add the view if necessary
|
||||
if let detailViewController = detailViewController, let scrollView = progressContentScrollView where detailViewController.view.superview == nil {
|
||||
addChildViewController(detailViewController)
|
||||
detailViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
scrollView.addSubview(detailViewController.view)
|
||||
detailViewController.didMoveToParentViewController(self)
|
||||
}
|
||||
|
||||
// Setup the constraints
|
||||
if let detail = detailViewController?.view, let scrollView = progressContentScrollView {
|
||||
// Create the constraints between the content view and the scroll view.
|
||||
detail.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
|
||||
detail.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
|
||||
detail.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
|
||||
detail.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
|
||||
// Create the constraints between the content view and the main view.
|
||||
detail.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
|
||||
detail.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true
|
||||
detail.bottomAnchor.constraintGreaterThanOrEqualToAnchor(view.bottomAnchor).active = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,171 +0,0 @@
|
||||
//
|
||||
// BaseExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/25/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
Runs the given closure after a delay.
|
||||
|
||||
- parameter delay: The amount of time in seconds before the closure is run.
|
||||
- parameter closure: The closure to run after the delay.
|
||||
*/
|
||||
func delay(delay:Double, closure:()->()) {
|
||||
dispatch_after(
|
||||
dispatch_time(
|
||||
DISPATCH_TIME_NOW,
|
||||
Int64(delay * Double(NSEC_PER_SEC))
|
||||
),
|
||||
dispatch_get_main_queue(), closure)
|
||||
}
|
||||
|
||||
/// The base view controller for example view controllers.
|
||||
class BaseExampleViewController: UIViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The button that will start a progress animation.
|
||||
@IBOutlet var progressButton: UIButton?
|
||||
|
||||
/// The slider that allows the user to control the progress manually.
|
||||
@IBOutlet var progressSlider: UISlider?
|
||||
|
||||
/// The switch that allows the user to switch the progress view between a determinate and indeterminate state.
|
||||
@IBOutlet var indeterminateSwitch: UISwitch?
|
||||
|
||||
/// The segmented control that allows the user to switch between the different possible states.
|
||||
@IBOutlet var stateControl: UISegmentedControl?
|
||||
|
||||
/// Returns the progress views controlled by the view controller.
|
||||
var progressViews: [M13ProgressView] {
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
The action that will run the progress animation for the progress views. This should be overriden and `animateProgressForProgressViews:completion:` should be called.
|
||||
- parameter sender: The button that called the action.
|
||||
*/
|
||||
@IBAction func beginProgressAnimation(sender: UIButton) {
|
||||
animateProgress({})
|
||||
}
|
||||
|
||||
/**
|
||||
The action that will update the progress of the progress views.
|
||||
- parameter sender: The slider whose value has changed.
|
||||
*/
|
||||
@IBAction func updateProgress(sender: UISlider) {
|
||||
for progressView in progressViews {
|
||||
progressView.setProgress(CGFloat(sender.value), animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The action that will update the indeterminate state of the progress views.
|
||||
- parameter sender: The switch whose value has changed.
|
||||
*/
|
||||
@IBAction func updateIndeterminate(sender: UISwitch) {
|
||||
for progressView in progressViews {
|
||||
progressView.indeterminate = sender.on
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The action that will update the state of the progress views.
|
||||
- parameter sender: The switch whose value has changed.
|
||||
*/
|
||||
@IBAction func updateState(sender: UISegmentedControl) {
|
||||
var state: M13ProgressViewState = .Normal
|
||||
if sender.selectedSegmentIndex == 1 {
|
||||
state = .Success
|
||||
} else if sender.selectedSegmentIndex == 2 {
|
||||
state = .Failure
|
||||
}
|
||||
|
||||
for progressView in progressViews {
|
||||
progressView.setState(state, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Animations
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Animates the progress of the progress views passed into the function. Once the animation completes, the completion block will be run.
|
||||
- parameter completion: The block of code to run on completion.
|
||||
- note: The completion block should be used to enable any controls that were disabled before the animation.
|
||||
*/
|
||||
func animateProgress(completion:()->()) {
|
||||
|
||||
// Disable controls for the duration of the animation.
|
||||
progressButton?.enabled = false
|
||||
progressSlider?.enabled = false
|
||||
indeterminateSwitch?.enabled = false
|
||||
stateControl?.enabled = false
|
||||
|
||||
// Set the initial progress to zero
|
||||
for progressView in progressViews {
|
||||
progressView.setProgress(0.0, animated: false)
|
||||
}
|
||||
|
||||
// Weak self to prevent retain loop.
|
||||
weak var weakSelf: BaseExampleViewController? = self
|
||||
let shownProgressViews: [M13ProgressView] = progressViews
|
||||
delay(1.0) { () -> () in
|
||||
for progressView in shownProgressViews {
|
||||
progressView.setProgress(0.3, animated: true)
|
||||
}
|
||||
delay(2.0, closure: { () -> () in
|
||||
for progressView in shownProgressViews {
|
||||
progressView.setProgress(0.5, animated: true)
|
||||
}
|
||||
delay(3.0, closure: { () -> () in
|
||||
for progressView in shownProgressViews {
|
||||
progressView.setProgress(1.0, animated: true)
|
||||
}
|
||||
if let aProgressView = shownProgressViews.first {
|
||||
delay(aProgressView.animationDuration, closure: { () -> () in
|
||||
for progressView in shownProgressViews {
|
||||
progressView.setState(.Success, animated: true)
|
||||
}
|
||||
delay(2.0, closure: { () -> () in
|
||||
if let retainedSelf = weakSelf {
|
||||
for progressView in shownProgressViews {
|
||||
progressView.setState(.Normal, animated: true)
|
||||
progressView.setProgress(CGFloat(retainedSelf.progressSlider!.value), animated: true)
|
||||
}
|
||||
|
||||
retainedSelf.progressButton?.enabled = true
|
||||
retainedSelf.progressSlider?.enabled = true
|
||||
retainedSelf.indeterminateSwitch?.enabled = true
|
||||
retainedSelf.stateControl?.enabled = true
|
||||
completion()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// FilteredImageExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/28/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FilteredImageExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The progress view.
|
||||
@IBOutlet var filteredImageProgressView: M13ProgressFilteredImage?
|
||||
|
||||
/// The control that allows the user to select a filter.
|
||||
@IBOutlet var filterControl: UISegmentedControl?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let filteredImageProgressView = filteredImageProgressView {
|
||||
return [filteredImageProgressView]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
@IBAction func updateFilter(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
filteredImageProgressView?.progressFilter = .Blur
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
filteredImageProgressView?.progressFilter = .LightTunnel
|
||||
} else if sender.selectedSegmentIndex == 2 {
|
||||
filteredImageProgressView?.progressFilter = .SepiaTone
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
//
|
||||
// GreyscaleImageExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/28/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class GreyscaleImageExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The progress view.
|
||||
@IBOutlet var greyscaleImageProgressView: M13ProgressImage?
|
||||
|
||||
/// Changes the direction of the progress
|
||||
@IBOutlet var directionControl: UISegmentedControl?
|
||||
|
||||
/// Shows the gresscale background
|
||||
@IBOutlet var showBackgroundSwitch: UISwitch?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let greyscaleImageProgressView = greyscaleImageProgressView {
|
||||
return [greyscaleImageProgressView]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Changes the direction progress travels in.
|
||||
- parameter sender: The segmented control whose value has changed.
|
||||
*/
|
||||
@IBAction func updateDirection(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
greyscaleImageProgressView?.progressDirection = .LeadingToTrailing
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
greyscaleImageProgressView?.progressDirection = .BottomToTop
|
||||
} else if sender.selectedSegmentIndex == 2 {
|
||||
greyscaleImageProgressView?.progressDirection = .TrailingToLeading
|
||||
} else if sender.selectedSegmentIndex == 3 {
|
||||
greyscaleImageProgressView?.progressDirection = .TopToBottom
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func updateBackgroundSwitch(sender: UISwitch) {
|
||||
greyscaleImageProgressView?.drawGreyscaleBackground = sender.on
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,45 +13,12 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UIStatusBarTintParameters</key>
|
||||
<dict>
|
||||
<key>UINavigationBar</key>
|
||||
<dict>
|
||||
<key>Style</key>
|
||||
<string>UIBarStyleDefault</string>
|
||||
<key>Translucent</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// M13ProgressSuite.h
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 8/7/16.
|
||||
// Copyright © 2016 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for M13ProgressSuite.
|
||||
FOUNDATION_EXPORT double M13ProgressSuiteVersionNumber;
|
||||
|
||||
//! Project version string for M13ProgressSuite.
|
||||
FOUNDATION_EXPORT const unsigned char M13ProgressSuiteVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <M13ProgressSuite/PublicHeader.h>
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
//
|
||||
// MasterViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/25/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// An object that represents an example that the user can display.
|
||||
struct ProgressExample {
|
||||
/// The title of the example.
|
||||
let title: String
|
||||
/// The identifier of the example view controller.
|
||||
let viewControllerIdentifier: String
|
||||
}
|
||||
|
||||
/// An object that represents a group of examples that the user can display.
|
||||
struct ProgressExampleGroup {
|
||||
/// The title of the group.
|
||||
let title: String
|
||||
/// The examples contained within the section.
|
||||
let examples: [ProgressExample]
|
||||
}
|
||||
|
||||
/// The view controller that presents the menu allowing one to select a progress example.
|
||||
class MasterViewController: UITableViewController {
|
||||
|
||||
//-----------------------------
|
||||
// MARK: - Properties
|
||||
//-----------------------------
|
||||
|
||||
/// The currently presented detail view controller.
|
||||
var detailViewController: DetailViewController? = nil
|
||||
|
||||
/// The list of possible examples.
|
||||
var exampleGroups: [ProgressExampleGroup] = [
|
||||
ProgressExampleGroup(title: "Progress Bars", examples: [
|
||||
ProgressExample(title: "Basic Progress Bar", viewControllerIdentifier: "basicBarViewController"),
|
||||
ProgressExample(title: "Bordered Progress Bar", viewControllerIdentifier: "borderedBarViewController")
|
||||
]),
|
||||
ProgressExampleGroup(title: "Circular Progress Indicators", examples: [
|
||||
ProgressExample(title: "Pie", viewControllerIdentifier: "pieViewController"),
|
||||
ProgressExample(title: "Ring", viewControllerIdentifier: "ringViewController"),
|
||||
ProgressExample(title: "Segmented Ring", viewControllerIdentifier: "segmentedRingViewController")
|
||||
]),
|
||||
ProgressExampleGroup(title: "Image Based Progress Indicators", examples: [
|
||||
ProgressExample(title: "Greyscale Image", viewControllerIdentifier: "greyscaleImageViewController"),
|
||||
ProgressExample(title: "Filtered Image", viewControllerIdentifier: "filteredImageViewController")
|
||||
])
|
||||
]
|
||||
|
||||
var objects = [AnyObject]()
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
if let split = self.splitViewController {
|
||||
let controllers = split.viewControllers
|
||||
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool) {
|
||||
self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
func insertNewObject(sender: AnyObject) {
|
||||
objects.insert(NSDate(), atIndex: 0)
|
||||
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
|
||||
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
|
||||
}
|
||||
|
||||
// MARK: - Segues
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
// Segue to update the detail view controller.
|
||||
if segue.identifier == "showDetail" {
|
||||
if let indexPath = self.tableView.indexPathForSelectedRow {
|
||||
// Get the example.
|
||||
let example = exampleGroups[indexPath.section].examples[indexPath.row]
|
||||
let exampleViewController = UIStoryboard(name: "Examples", bundle: nil).instantiateViewControllerWithIdentifier(example.viewControllerIdentifier)
|
||||
|
||||
// Set it to the detail controller.
|
||||
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
|
||||
controller.detailViewController = exampleViewController
|
||||
controller.title = example.title
|
||||
|
||||
// Update the navigation items.
|
||||
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
|
||||
controller.navigationItem.leftItemsSupplementBackButton = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Table View
|
||||
|
||||
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
||||
return exampleGroups.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return exampleGroups[section].examples.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return exampleGroups[section].title
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
|
||||
|
||||
let example = exampleGroups[indexPath.section].examples[indexPath.row]
|
||||
cell.textLabel!.text = example.title
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// PieExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/27/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class PieExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The progress view.
|
||||
@IBOutlet var pieProgressView: M13ProgressPie?
|
||||
|
||||
/// The control to change the direction of the progress.
|
||||
@IBOutlet var directionControl: UISegmentedControl?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let pieProgressView = pieProgressView {
|
||||
return [pieProgressView]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Changes the direction progress travels in.
|
||||
- parameter sender: The segmented control whose value has changed.
|
||||
*/
|
||||
@IBAction func updateDirection(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
pieProgressView?.progressDirection = .Clockwise
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
pieProgressView?.progressDirection = .CounterClockwise
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
//
|
||||
// RingExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/27/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class RingExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The progress view.
|
||||
@IBOutlet var ringProgressView: M13ProgressRing?
|
||||
|
||||
/// The switch to control whether or not the percentage is shown.
|
||||
@IBOutlet var showPercentageSwitch: UISwitch?
|
||||
|
||||
/// The control to change the direction of the progress.
|
||||
@IBOutlet var directionControl: UISegmentedControl?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let ringProgressView = ringProgressView {
|
||||
return [ringProgressView]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Shows and hides the percentage label in the progress ring.
|
||||
- parameter sender: The switch whose value has changed.
|
||||
*/
|
||||
@IBAction func updatePercentage(sender: UISwitch) {
|
||||
ringProgressView?.percentage = sender.on
|
||||
}
|
||||
|
||||
/**
|
||||
Changes the direction progress travels in.
|
||||
- parameter sender: The segmented control whose value has changed.
|
||||
*/
|
||||
@IBAction func updateDirection(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
ringProgressView?.progressDirection = .Clockwise
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
ringProgressView?.progressDirection = .CounterClockwise
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
//
|
||||
// SegmentedRingExampleViewController.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 11/27/15.
|
||||
// Copyright © 2015 Marxon13. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SegmentedRingExampleViewController: BaseExampleViewController {
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Properties
|
||||
//-------------------------------
|
||||
|
||||
/// The progress view.
|
||||
@IBOutlet var segmentedRingProgressView: M13ProgressSegmentedRing?
|
||||
|
||||
/// The switch to control whether or not the percentage is shown.
|
||||
@IBOutlet var showPercentageSwitch: UISwitch?
|
||||
|
||||
/// The control to control the segment shape
|
||||
@IBOutlet var segmentBoundaryControl: UISegmentedControl?
|
||||
|
||||
/// The control to change the direction of the progress.
|
||||
@IBOutlet var directionControl: UISegmentedControl?
|
||||
|
||||
override var progressViews: [M13ProgressView] {
|
||||
if let ringProgressView = segmentedRingProgressView {
|
||||
return [ringProgressView]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Initalization
|
||||
//-------------------------------
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// MARK: Actions
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
Shows and hides the percentage label in the progress ring.
|
||||
- parameter sender: The switch whose value has changed.
|
||||
*/
|
||||
@IBAction func updatePercentage(sender: UISwitch) {
|
||||
segmentedRingProgressView?.percentage = sender.on
|
||||
}
|
||||
|
||||
/**
|
||||
Changes the direction progress travels in.
|
||||
- parameter sender: The segmented control whose value has changed.
|
||||
*/
|
||||
@IBAction func updateDirection(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
segmentedRingProgressView?.progressDirection = .Clockwise
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
segmentedRingProgressView?.progressDirection = .CounterClockwise
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the shape of the segment wedges.
|
||||
- parameter sender: The control whose value was updated.
|
||||
*/
|
||||
@IBAction func updateSegmentBoundary(sender: UISegmentedControl) {
|
||||
if sender.selectedSegmentIndex == 0 {
|
||||
segmentedRingProgressView?.segmentBoundaryType = .Wedge
|
||||
} else if sender.selectedSegmentIndex == 1 {
|
||||
segmentedRingProgressView?.segmentBoundaryType = .Rectangle
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
2.0.0
|
||||
=====
|
||||
|
||||
The 2.0.0 update is coming! Now that I have some time, I'll be updating M13ProgressSuite to Swift. Along with the conversion, I'll be making some updates under the hood to make M13ProgressSuite more reliable. Interface Builder support is also on its way. Even though I have time to do this update, I don't have unlimited time to work on the library. So all fixes and feature requests that are not pull requests will be added to version 2.0.0. I've published the base project, as all that needs to happen now is converting the individual progress views to swift. If anyone wants to lend a hand that would be greatly appreciated.
|
||||
|
||||
Thanks,
|
||||
Brandon
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
**Repo**
|
||||
- Update readme to include small gifs.
|
||||
- Add .io site for complete example list and property examples, with images of what property changes will do.
|
||||
- Add generated documentation to .io site.
|
||||
- Add CI service.
|
||||
- Add direction and ideas list to .io site.
|
||||
|
||||
**Overall**
|
||||
- Support NSCoding protocol on all classes.
|
||||
- Support NSCopying protocol on all classes.
|
||||
- Add animations and transitions for all possible visual changes that would be user-visible.
|
||||
- Move icon generation into own class. Pass draw rect for icon, size of icon. Make it easier to override with custom icons.
|
||||
- New icons that fit iOS 7+ style.
|
||||
- Add optional animation completion blocks to setState and setProgress.
|
||||
- Possibly move some requirements from M13ProgressView class / subclasses to protocols. Like some shared requirements for the segmented progress views.
|
||||
- Add wrapper to display percentage outside of progress view: leading, trailing, above, below.
|
||||
|
||||
**Examples**
|
||||
- Fix crash when phone is in portrait mode.
|
||||
- Make layouts of all examples vertically scrollable.
|
||||
- Include controls to change all parameters except for color.
|
||||
- Make layouts dynamic. No controls should overlap.
|
||||
- Add app extension example.
|
||||
- Research and Add watch OS example. (After everything else is done)
|
||||
|
||||
**Ring**
|
||||
- Add stroke animation for x and "check" when shown, fade when hide.
|
||||
- Add boolean to set the bar background color to the tint color instead of secondary.
|
||||
- Multistage animation for indeterminate transition.
|
||||
- Decrease width of progress bar.
|
||||
- Animate in the gap in the progress background.
|
||||
- Start rotating the progress background.
|
||||
- When finished, complete a revolution before closing the gap.
|
||||
|
||||
**Navigation Bar**
|
||||
- Custom height of progress bar.
|
||||
- Custom progress bar offset.
|
||||
- Prefix all methods with "m13_" to avoid conflicts.
|
||||
|
||||
**Segmented Progress Views**
|
||||
- Add support for an array of primary colors.
|
||||
|
||||
**Console**
|
||||
- Remove? Not up to par with the rest of the controls. Can't see use case for it.
|
||||
|
||||
**Filtered Image**
|
||||
- Pre-render images? Provide hook for ΔProgress to render images for? Therefore fixing issues with lag.
|
||||
|
||||
**Image**
|
||||
- Rename to greyscale image.
|
||||
|
||||
**Pie**
|
||||
- Better indeterminate animation.
|
||||
- Hide progress once finished when switching to non-normal state.
|
||||
|
||||
**HUD**
|
||||
- Add option of buttons to allow cancelation of current activity.
|
||||
|
||||
M13ProgressSuite
|
||||
================
|
||||
|
||||
A collection of easy to use progress views for iOS applications. The collection includes progress views of many types (bar, ring, etc.), an UINavigationBar with progress bar, and a HUD overlay. Everything in the collection is easily styled through code or Interface Builder, and is simple to update.
|
||||
|
||||
Checkout the [M13ProgressSuite website](marxon13.github.io/M13ProgressSuite) to see more examples and documentation.
|
||||
|
||||
Features:
|
||||
---------
|
||||
* All progress views inherit from the same base class, making it easy to use multiple kinds of progress views in a project, or swap kinds of progress views.
|
||||
* The progress views have a determinate state, indeterminate state, success state, and failure state.
|
||||
* All the progress views are IBDesignable.
|
||||
* It is very easy to make custom progress views, as the base class handles the grunt work of the animation. Just write the code to display a specific progress value, as well as the indeterminate, success and failure states.
|
||||
|
||||
Contact Me:
|
||||
-------------
|
||||
If you have any questions comments or suggestions, send me a message. If you find a bug, or want to submit a pull request, let me know.
|
||||
|
||||
License:
|
||||
--------
|
||||
MIT License
|
||||
|
||||
> Copyright (c) 2015 Brandon McQuilkin
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining
|
||||
>a copy of this software and associated documentation files (the
|
||||
>"Software"), to deal in the Software without restriction, including
|
||||
>without limitation the rights to use, copy, modify, merge, publish,
|
||||
>distribute, sublicense, and/or sell copies of the Software, and to
|
||||
>permit persons to whom the Software is furnished to do so, subject to
|
||||
>the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be
|
||||
>included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
>EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
>MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
>IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
>CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
>TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
>SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,279 @@
|
||||
//
|
||||
// M13ProgressBar.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon (NonEmp) on 8/8/16.
|
||||
// Copyright © 2016 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible directions a progress bar can travel in.
|
||||
|
||||
- **leadingToTrailing**: The progress bar will travel from leading to trailing as the progress nears completion.
|
||||
- **trailingToLeading**: The progress bar will travel from trailing to leading as the progress nears completion.
|
||||
- **bottomToTop**: The progress bar will travel from the bottom to the top as the progress nears completion.
|
||||
- **topToBottom**: The progress bar will travel from the top to the bottom as the progress nears completion.
|
||||
*/
|
||||
public enum M13ProgressBarProgressDirection: Int, RawRepresentable {
|
||||
/// The progress bar will travel from leading to trailing as the progress nears completion.
|
||||
case leadingToTrailing
|
||||
/// The progress bar will travel from trailing to leading as the progress nears completion.
|
||||
case trailingToLeading
|
||||
/// The progress bar will travel from the bottom to the top as the progress nears completion.
|
||||
case bottomToTop
|
||||
/// The progress bar will travel from the top to the bottom as the progress nears completion.
|
||||
case topToBottom
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
A simple progress bar that can display determinate and indeterminate progress.
|
||||
*/
|
||||
@IBDesignable
|
||||
public class M13ProgressBar: M13ProgressViewBase, M13ProgressViewMultipleType {
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Initalization
|
||||
// ---------------------------------
|
||||
|
||||
override init() {
|
||||
super.init(frame: CGRect.zero)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
|
||||
cornerRadius = CGFloat(aDecoder.decodeDouble(forKey: "cornerRadius"))
|
||||
if let direction = aDecoder.decodeObject(forKey: "progressDirection") as? String {
|
||||
_IBprogressDirection = direction
|
||||
}
|
||||
sharedSetup()
|
||||
}
|
||||
|
||||
public override func encode(with aCoder: NSCoder) {
|
||||
super.encode(with: aCoder)
|
||||
|
||||
aCoder.encode(cornerRadius, forKey: "cornerRadius")
|
||||
aCoder.encode(_IBprogressDirection, forKey: "progressDirection")
|
||||
}
|
||||
|
||||
override func sharedSetup() {
|
||||
super.sharedSetup()
|
||||
|
||||
// Setup the defaults
|
||||
clipsToBounds = true
|
||||
|
||||
setAppropiateCornerRadius()
|
||||
|
||||
layer.backgroundColor = secondaryTintColor?.cgColor
|
||||
progressLayer.backgroundColor = tintColor.cgColor
|
||||
|
||||
progressLayer.actions = [
|
||||
"frame": NSNull(),
|
||||
"anchorPoint": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
"cornerRadius": NSNull()
|
||||
]
|
||||
|
||||
layer.addSublayer(progressLayer)
|
||||
}
|
||||
|
||||
public override func prepareForInterfaceBuilder() {
|
||||
sharedSetup()
|
||||
super.prepareForInterfaceBuilder()
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Properties
|
||||
// ---------------------------------
|
||||
|
||||
@IBInspectable override public var secondaryTintColor: UIColor? {
|
||||
didSet {
|
||||
layer.backgroundColor = secondaryTintColor?.cgColor
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var cornerRadius: CGFloat = CGFloat.greatestFiniteMagnitude {
|
||||
didSet {
|
||||
setAppropiateCornerRadius()
|
||||
}
|
||||
}
|
||||
|
||||
public var progressDirection: M13ProgressBarProgressDirection = .leadingToTrailing {
|
||||
didSet {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public var determinatePropertyAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator(duration: 0.3, curve: .easeIn, animations: nil)
|
||||
|
||||
public var indeterminatePropertyAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .easeInOut, animations: nil)
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Progress
|
||||
// ---------------------------------
|
||||
|
||||
private var _progress: CGFloat = 0.0
|
||||
@IBInspectable public var progress: CGFloat {
|
||||
get {
|
||||
return _progress
|
||||
}
|
||||
set {
|
||||
setProgress(newValue, animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func setProgress(_ progress: CGFloat, animated: Bool, completion: ((progress: CGFloat) -> Void)?) {
|
||||
// Only adjust if we are showing determinate progress.
|
||||
guard type == .determinate else {
|
||||
return
|
||||
}
|
||||
|
||||
// Adjusted progress
|
||||
let adjustedProgress = max(min(progress, 1.0), 0.0)
|
||||
|
||||
// If we are not animated, end any animations and set the proper frame to the progress layer
|
||||
if !animated {
|
||||
determinatePropertyAnimator.stopAnimation(false)
|
||||
progressLayer.frame = CGRect(x: 0.0, y: 0.0, width: frame.size.width * adjustedProgress, height: frame.height)
|
||||
return
|
||||
}
|
||||
|
||||
// Adjust the animation for the new progress value.
|
||||
let durationFactor = determinatePropertyAnimator.fractionComplete
|
||||
determinatePropertyAnimator.stopAnimation(false)
|
||||
determinatePropertyAnimator.finishAnimation(at: .current)
|
||||
|
||||
determinatePropertyAnimator.addAnimations { [unowned self] in
|
||||
self._progress = adjustedProgress
|
||||
self.progressLayer.frame = CGRect(x: 0.0, y: 0.0, width: self.frame.size.width * adjustedProgress, height: self.frame.height)
|
||||
}
|
||||
|
||||
determinatePropertyAnimator.addCompletion { (position) in
|
||||
completion?(progress: adjustedProgress)
|
||||
}
|
||||
|
||||
// Restart the animation.
|
||||
determinatePropertyAnimator.startAnimation()
|
||||
determinatePropertyAnimator.pauseAnimation()
|
||||
determinatePropertyAnimator.continueAnimation(withTimingParameters: nil, durationFactor: durationFactor)
|
||||
}
|
||||
|
||||
private var _type: M13ProgressType = .determinate
|
||||
public var type: M13ProgressType {
|
||||
get {
|
||||
return _type
|
||||
}
|
||||
set {
|
||||
setType(newValue, animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func setType(_ type: M13ProgressType, animated: Bool, completion: ((type: M13ProgressType) -> Void)?) {
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - UI
|
||||
// ---------------------------------
|
||||
|
||||
private var progressLayer: CAShapeLayer = CAShapeLayer()
|
||||
|
||||
public override func tintColorDidChange() {
|
||||
super.tintColorDidChange()
|
||||
progressLayer.backgroundColor = tintColor.cgColor
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Layout
|
||||
// ---------------------------------
|
||||
|
||||
public override var intrinsicContentSize: CGSize {
|
||||
return CGSize(width: UIViewNoIntrinsicMetric, height: UIViewNoIntrinsicMetric)
|
||||
}
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
setAppropiateCornerRadius()
|
||||
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Other
|
||||
// ---------------------------------
|
||||
|
||||
private func setAppropiateCornerRadius() {
|
||||
var appropiateCornerRadius = min(frame.size.width / 2.0, frame.size.height / 2.0)
|
||||
appropiateCornerRadius = min(appropiateCornerRadius, cornerRadius)
|
||||
progressLayer.cornerRadius = appropiateCornerRadius
|
||||
layer.cornerRadius = appropiateCornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
// Interface builder support extension.
|
||||
extension M13ProgressBar {
|
||||
|
||||
@IBInspectable public var _IBprogressDirection: String {
|
||||
get {
|
||||
switch progressDirection {
|
||||
case .leadingToTrailing:
|
||||
return "leadingToTrailing"
|
||||
case .trailingToLeading:
|
||||
return "trailingToLeading"
|
||||
case .bottomToTop:
|
||||
return "bottomToTop"
|
||||
case .topToBottom:
|
||||
return "topToBottom"
|
||||
}
|
||||
}
|
||||
set {
|
||||
switch newValue {
|
||||
case "leadingToTrailing":
|
||||
progressDirection = .leadingToTrailing
|
||||
break
|
||||
case "trailingToLeading":
|
||||
progressDirection = .trailingToLeading
|
||||
break
|
||||
case "bottomToTop":
|
||||
progressDirection = .bottomToTop
|
||||
break
|
||||
case "topToBottom":
|
||||
progressDirection = .topToBottom
|
||||
break
|
||||
default:
|
||||
progressDirection = .leadingToTrailing
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var _IBIndeterminate: Bool {
|
||||
get {
|
||||
switch type {
|
||||
case .determinate:
|
||||
return false
|
||||
case .indeterminate:
|
||||
return true
|
||||
}
|
||||
}
|
||||
set {
|
||||
if newValue {
|
||||
type = .indeterminate
|
||||
} else {
|
||||
type = .determinate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// M13ProgressState.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 8/7/16.
|
||||
// Copyright © 2016 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
/**
|
||||
The possible states of progress views.
|
||||
|
||||
- **normal**: The progress view is in its normal state of displaying progress.
|
||||
- **success**: The progress view displays an indicator that the operation completed successfully.
|
||||
- **failure**: The progress view displays an indicator that the operation failed.
|
||||
*/
|
||||
public enum M13ProgressState {
|
||||
/// The progress view is in its normal state of displaying progress.
|
||||
case progressing
|
||||
/// The progress view displays an indicator that the operation completed successfully.
|
||||
case success
|
||||
/// The progress view displays an indicator that the operation failed.
|
||||
case failure
|
||||
}
|
||||
|
||||
/**
|
||||
A protocol that provides structure for progress views that have success and failure states.
|
||||
*/
|
||||
public protocol M13ProgressViewState {
|
||||
|
||||
/**
|
||||
The current state of the progress view.
|
||||
*/
|
||||
var state: M13ProgressState { get set }
|
||||
|
||||
/**
|
||||
Set the state of the progress view, with the option of animating the state change.
|
||||
- parameter state: The new state of the progress view.
|
||||
- parameter animated: Whether or no to animate the change.
|
||||
- parameter completion: The completion block to run once the animation has finsihed.
|
||||
*/
|
||||
func setState(_ state: M13ProgressState, animated: Bool, completion: ((state: M13ProgressState) -> Void)?)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// M13ProgressIndeterminate.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 8/7/16.
|
||||
// Copyright © 2016 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
The possible types of progress the progress views can display.
|
||||
|
||||
- **determinate**: The amount of progress made or the time remaining is known.
|
||||
- **indeterminate**: The amount of progress and the remaining time is unknown.
|
||||
*/
|
||||
public enum M13ProgressType {
|
||||
/// The amount of progress made or the time remaining is known.
|
||||
case determinate
|
||||
/// The amount of progress and the remaining time is unknown.
|
||||
case indeterminate
|
||||
}
|
||||
|
||||
/**
|
||||
A protocol that provides the structure for determinate progress views.
|
||||
*/
|
||||
public protocol M13ProgressViewDeterminate {
|
||||
|
||||
/**
|
||||
The progress displayed to the user as a percentage from 0.0 to 1.0.
|
||||
*/
|
||||
var progress: CGFloat { get set }
|
||||
|
||||
/**
|
||||
Set the progress of the progress view, with the option of animating the change.
|
||||
- parameter progress: The amount of progress that has been made.
|
||||
- parameter animated: Whether or no to animate the change.
|
||||
- parameter completion: The completion block to run once the animation has finished.
|
||||
*/
|
||||
func setProgress(_ progress: CGFloat, animated: Bool, completion: ((progress: CGFloat) -> Void)?)
|
||||
|
||||
/**
|
||||
The property animator that controls the determinate progress animations.
|
||||
- warning: Wait until all animations are complete before changing the property animator.
|
||||
*/
|
||||
var determinatePropertyAnimator: UIViewPropertyAnimator { get set }
|
||||
}
|
||||
|
||||
/**
|
||||
A protocol that provides the structure for indeterminate progress views.
|
||||
*/
|
||||
public protocol M13ProgressViewIndeterminate {
|
||||
|
||||
/**
|
||||
The property animator that controls the indeterminate progress animations.
|
||||
- warning: Wait until all animations are complete before changing the property animator.
|
||||
*/
|
||||
var indeterminatePropertyAnimator: UIViewPropertyAnimator { get set }
|
||||
}
|
||||
|
||||
/**
|
||||
A protocol that provides structure for progress views that can show both determinate and indeterminate progress.
|
||||
*/
|
||||
public protocol M13ProgressViewMultipleType: M13ProgressViewDeterminate, M13ProgressViewIndeterminate {
|
||||
|
||||
/**
|
||||
The type of progress the progress view is displaying.
|
||||
*/
|
||||
var type: M13ProgressType { get set }
|
||||
|
||||
/**
|
||||
Set the type of progress the progress view is displaying, with the option of animating the change.
|
||||
- parameter type: The new type of the progress the progress view will display.
|
||||
- parameter animated: Whether or no to animate the change.
|
||||
- parameter completion: The completion block to run once the animation has finished.
|
||||
*/
|
||||
func setType(_ type: M13ProgressType, animated: Bool, completion: ((type: M13ProgressType) -> Void)?)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// M13ProgressView.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon on 8/7/16.
|
||||
// Copyright © 2016 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
A standardized base upon which to build progress views for applications. This allows one to use any progress view in any component that use this standard.
|
||||
*/
|
||||
public protocol M13ProgressView {
|
||||
|
||||
/// A secondary tint color for the progress view.
|
||||
var secondaryTintColor: UIColor? { get set }
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// M13ProgressViewBase.swift
|
||||
// M13ProgressSuite
|
||||
//
|
||||
// Created by McQuilkin, Brandon (NonEmp) on 8/8/16.
|
||||
// Copyright © 2016 Brandon McQuilkin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
public class M13ProgressViewBase: UIView, M13ProgressView {
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Initalization
|
||||
// ---------------------------------
|
||||
|
||||
init() {
|
||||
super.init(frame: CGRect.zero)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
|
||||
secondaryTintColor = aDecoder.decodeObject(forKey: "secondaryTintColor") as? UIColor
|
||||
}
|
||||
|
||||
public override func encode(with aCoder: NSCoder) {
|
||||
super.encode(with: aCoder)
|
||||
|
||||
aCoder.encode(secondaryTintColor, forKey: "secondaryTintColor")
|
||||
}
|
||||
|
||||
/**
|
||||
The setup shared between the various initalizers.
|
||||
*/
|
||||
internal func sharedSetup() {
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// MARK: - Properties
|
||||
// ---------------------------------
|
||||
|
||||
@IBInspectable public var secondaryTintColor: UIColor?
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user