circle progress

This commit is contained in:
Pfeil, Scott Robert 2020-01-13 10:20:11 -05:00
parent 5bb6b9bc75
commit 1b06d7007b
3 changed files with 149 additions and 115 deletions

View File

@ -124,6 +124,7 @@
D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */; };
D28A837F23CCA96400DFE4FC /* TabsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837E23CCA96400DFE4FC /* TabsModel.swift */; };
D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */; };
D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */; };
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; };
D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -383,6 +384,7 @@
D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsListItemModel.swift; sourceTree = "<group>"; };
D28A837E23CCA96400DFE4FC /* TabsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsModel.swift; sourceTree = "<group>"; };
D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionListItemModel.swift; sourceTree = "<group>"; };
D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleProgressModel.swift; sourceTree = "<group>"; };
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = "<group>"; };
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = "<group>"; };
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = "<group>"; };
@ -1040,6 +1042,7 @@
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */,
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */,
01004F2F22721C3800991ECC /* RadioButton.swift */,
D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */,
943784F3236B77BB006A1E82 /* GraphView.swift */,
943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */,
);
@ -1399,6 +1402,7 @@
012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */,
D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */,
01EB369023609801006832FA /* ListItemModel.swift in Sources */,
D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */,
D268C70C2386DFFD007F2C1C /* StackItemModel.swift in Sources */,
DBEFFA04225A829700230692 /* Label.swift in Sources */,
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,

View File

@ -0,0 +1,128 @@
//
// CircleProgressModel.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 1/13/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import UIKit
public enum GraphSize: String, Codable {
case small, medium, large
}
public enum GraphStyle: String, Codable {
case unlimited, safetyMode
}
public class CircleProgressModel: MoleculeProtocol {
public static var identifier: String = "circleProgress"
public var style: GraphStyle = .unlimited {
didSet {
updateStyle()
}
}
public var size: GraphSize = .small {
didSet {
updateSize()
}
}
public var diameter: CGFloat = 24
public var lineWidth: CGFloat = 5
public var clockwise: Bool = true
public var duration : Double = 1.0
public var colors = [Color]()
public var backgroundColor: Color?
public init() {}
enum CircleProgressCodingKeys: String, CodingKey {
case style
case size
case diameter
case lineWidth
case clockwise
case duration
case colors
case backgroundColor
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CircleProgressCodingKeys.self)
if let style = try typeContainer.decodeIfPresent(GraphStyle.self, forKey: .style) {
self.style = style
}
if let size = try typeContainer.decodeIfPresent(GraphSize.self, forKey: .size) {
self.size = size
}
if let diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) {
self.diameter = diameter
}
if let lineWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .lineWidth) {
self.lineWidth = lineWidth
}
if let clockwise = try typeContainer.decodeIfPresent(Bool.self, forKey: .clockwise) {
self.clockwise = clockwise
}
if let duration = try typeContainer.decodeIfPresent(Double.self, forKey: .duration) {
self.duration = duration
}
if let colors = try typeContainer.decodeIfPresent([Color].self, forKey: .colors) {
self.colors = colors
}
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CircleProgressCodingKeys.self)
try container.encode(style, forKey: .style)
try container.encode(size, forKey: .size)
try container.encode(diameter, forKey: .diameter)
try container.encode(lineWidth, forKey: .lineWidth)
try container.encode(clockwise, forKey: .clockwise)
try container.encode(duration, forKey: .duration)
try container.encode(colors, forKey: .colors)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
}
func getCGColorsFromArray(_ colorArray: [String]) -> [Color] {
return colorArray.map { (colorString) -> Color in
return Color(uiColor: UIColor.mfGet(forHex: colorString))
}
}
func updateStyle() {
switch style {
case .unlimited:
duration = 1.0
clockwise = true
//current style, only the end part shows darker look
colors = getCGColorsFromArray(["#007AB8","#007AB8","#033554"])
break
case .safetyMode:
duration = 1.5
clockwise = true
colors = getCGColorsFromArray(["#CC4D0F","#CC4D0F","AB0309"])
break
}
}
func updateSize() {
switch size {
case .small:
diameter = MFSizeObject(standardSize: 20)?.getValueBasedOnApplicationWidth() ?? 20
lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4
break
case .medium:
diameter = MFSizeObject(standardSize: 100)?.getValueBasedOnApplicationWidth() ?? 100
lineWidth = MFSizeObject(standardSize: 8)?.getValueBasedOnApplicationWidth() ?? 8
break
case .large:
diameter = MFSizeObject(standardSize: 180)?.getValueBasedOnApplicationWidth() ?? 180
lineWidth = MFSizeObject(standardSize: 12)?.getValueBasedOnApplicationWidth() ?? 12
break
}
}
}

View File

@ -8,113 +8,13 @@
import UIKit
enum GraphSize: String {
case small, medium, large
}
enum GraphStyle: String {
case unlimited, safetyMode
}
///Graph Object contains properties
public struct GraphObject {
var style: GraphStyle {
didSet {
updateStyle()
}
}
var size: GraphSize {
didSet {
updateSize()
}
}
var diameter: CGFloat = 24
var lineWidth: CGFloat = 5
var clockwise: Bool = true
var duration : Double = 1.0
var colors = [CGColor]()
public init(_ json: [AnyHashable : Any]?) {
style = .unlimited
size = .small
guard let json = json else {
return
}
if let styleString = json.optionalStringForKey("style") {
style = GraphStyle(rawValue: styleString) ?? .unlimited
}
if let sizeString = json.optionalStringForKey("size") {
size = GraphSize(rawValue: sizeString) ?? .small
}
updateStyle()
updateSize()
if let diameter = json.optionalCGFloatForKey("diameter") {
self.diameter = diameter
}
if let lineWidth = json.optionalCGFloatForKey("lineWidth") {
self.lineWidth = lineWidth
}
if let clockwise = json.optionalBoolForKey("clockwise") {
self.clockwise = clockwise
}
if let duration = json["duration"] as? Double {
self.duration = duration
}
if let colorArray = json.optionalArrayForKey("colors") as? [String] {
colors = getCGColorsFromArray(colorArray)
}
}
func getCGColorsFromArray(_ colorArray: [String]) -> [CGColor] {
return colorArray.map { (colorString) -> CGColor in
return UIColor.mfGet(forHex: colorString).cgColor
}
}
mutating func updateStyle() {
switch style {
case .unlimited:
duration = 1.0
clockwise = true
//current style, only the end part shows darker look
colors = getCGColorsFromArray(["#007AB8","#007AB8","#033554"])
break
case .safetyMode:
duration = 1.5
clockwise = true
colors = getCGColorsFromArray(["#CC4D0F","#CC4D0F","AB0309"])
break
}
}
//those are
mutating func updateSize() {
switch size {
case .small:
diameter = MFSizeObject(standardSize: 20)?.getValueBasedOnApplicationWidth() ?? 20
lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4
break
case .medium:
diameter = MFSizeObject(standardSize: 100)?.getValueBasedOnApplicationWidth() ?? 100
lineWidth = MFSizeObject(standardSize: 8)?.getValueBasedOnApplicationWidth() ?? 8
break
case .large:
diameter = MFSizeObject(standardSize: 180)?.getValueBasedOnApplicationWidth() ?? 180
lineWidth = MFSizeObject(standardSize: 12)?.getValueBasedOnApplicationWidth() ?? 12
break
}
}
}
@objcMembers open class GraphView: View, MVMCoreUIViewConstrainingProtocol {
var heightConstraint: NSLayoutConstraint?
var gradientLayer: CALayer?
var graphObject: GraphObject?
var graphModel: CircleProgressModel? {
return model as? CircleProgressModel
}
// MARK: setup
open override func setupView() {
@ -128,14 +28,16 @@ public struct GraphObject {
override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.setWithModel(model, delegateObject, additionalData)
guard let model = model as? CircleProgressModel else { return }
createGraphCircle(model)
rotationAnimation(model)
}
override open func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
let object = GraphObject(json)
graphObject = object
createGraphCircle(object)
rotationAnimation(object)
guard let graphModel = graphModel else { return }
createGraphCircle(graphModel)
rotationAnimation(graphModel)
}
class func getAngle(_ piValue: Double) -> Double {
@ -147,7 +49,7 @@ public struct GraphObject {
}
// MARK: circle
open func createGraphCircle(_ graphObject: GraphObject) {
open func createGraphCircle(_ graphObject: CircleProgressModel) {
if let sublayers = layer.sublayers {
for sublayer in sublayers {
sublayer.removeAllAnimations()
@ -188,14 +90,14 @@ public struct GraphObject {
| | |
-------------
*/
func createGradientLayer(_ graphObject: GraphObject) -> CALayer {
func createGradientLayer(_ graphObject: CircleProgressModel) -> CALayer {
let containLayer = CALayer()
containLayer.frame = CGRect(x: 0, y: 0, width: graphObject.diameter, height: graphObject.diameter)
let radius = graphObject.diameter / 2.0
//create graident layers
guard graphObject.colors.count > 1 else {
containLayer.backgroundColor = graphObject.colors.first
containLayer.backgroundColor = graphObject.colors.first?.uiColor.cgColor
return containLayer
}
var topGradientHeight : CGFloat = 0.0
@ -214,7 +116,7 @@ public struct GraphObject {
leftColors.removeLast()
topLayer.colors = [leftColors.last!, rightColors.first!]
} else {
topLayer.backgroundColor = leftColors.last
topLayer.backgroundColor = leftColors.last?.uiColor.cgColor
}
containLayer.addSublayer(topLayer)
@ -227,7 +129,7 @@ public struct GraphObject {
if leftColors.count > 1 {
leftLayer.colors = Array(leftColors)
} else {
leftLayer.backgroundColor = leftColors.first
leftLayer.backgroundColor = leftColors.first?.uiColor.cgColor
}
containLayer.addSublayer(leftLayer)
@ -238,7 +140,7 @@ public struct GraphObject {
if rightColors.count > 1 {
rightLayer.colors = Array(rightColors)
} else {
rightLayer.backgroundColor = rightColors.first
rightLayer.backgroundColor = rightColors.first?.uiColor.cgColor
}
containLayer.addSublayer(rightLayer)
@ -250,7 +152,7 @@ public struct GraphObject {
}
//MARK: Animation
func rotationAnimation(_ object: GraphObject) {
func rotationAnimation(_ object: CircleProgressModel) {
MVMCoreDispatchUtility.performBlock(onMainThread:{
let rotation = CABasicAnimation(keyPath: "transform.rotation")
let animationHandler = GraphViewAnimationHandler.shared
@ -281,7 +183,7 @@ public struct GraphObject {
extension GraphView: CAAnimationDelegate {
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let object = graphObject {
if let object = graphModel {
rotationAnimation(object)
}
}