circle progress
This commit is contained in:
parent
5bb6b9bc75
commit
1b06d7007b
@ -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 */,
|
||||
|
||||
128
MVMCoreUI/Atoms/Views/CircleProgressModel.swift
Normal file
128
MVMCoreUI/Atoms/Views/CircleProgressModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user