Refactor codes for circular progress UI.
This commit is contained in:
parent
1b0197ed2c
commit
20d818b2c2
@ -15,6 +15,10 @@ import UIKit
|
|||||||
return model as? CircularProgressBarModel
|
return model as? CircularProgressBarModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var viewWidth: CGFloat {
|
||||||
|
graphModel?.diameter ?? CGFloat(84)
|
||||||
|
}
|
||||||
|
|
||||||
private var progressLayer = CAShapeLayer()
|
private var progressLayer = CAShapeLayer()
|
||||||
private var tracklayer = CAShapeLayer()
|
private var tracklayer = CAShapeLayer()
|
||||||
private var labelLayer = CATextLayer()
|
private var labelLayer = CATextLayer()
|
||||||
@ -25,18 +29,16 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var setTrackColor: UIColor = UIColor.white {
|
var setTrackColor: UIColor = UIColor.lightGray {
|
||||||
didSet {
|
didSet {
|
||||||
tracklayer.strokeColor = setTrackColor.cgColor
|
tracklayer.strokeColor = setTrackColor.cgColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
A path that consists of straight and curved line segments that you can render in your custom views.
|
// A path with which CAShapeLayer will be drawn on the screen
|
||||||
Meaning our CAShapeLayer will now be drawn on the screen with the path we have specified here
|
|
||||||
*/
|
|
||||||
private var viewCGPath: CGPath? {
|
private var viewCGPath: CGPath? {
|
||||||
|
|
||||||
let width = graphModel?.diameter ?? 84
|
let width = viewWidth
|
||||||
let height = width
|
let height = width
|
||||||
|
|
||||||
return UIBezierPath(arcCenter: CGPoint(x: width / 2.0, y: height / 2.0),
|
return UIBezierPath(arcCenter: CGPoint(x: width / 2.0, y: height / 2.0),
|
||||||
@ -45,9 +47,51 @@ import UIKit
|
|||||||
endAngle: CGFloat(1.5 * Double.pi), clockwise: true).cgPath
|
endAngle: CGFloat(1.5 * Double.pi), clockwise: true).cgPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: setup
|
||||||
|
override open func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
heightConstraint = heightAnchor.constraint(equalToConstant: 0)
|
||||||
|
heightConstraint?.isActive = true
|
||||||
|
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
guard let model = model as? CircularProgressBarModel else { return }
|
||||||
|
|
||||||
|
// set background color
|
||||||
|
if let backgroundColor = model.backgroundColor {
|
||||||
|
self.backgroundColor = backgroundColor.uiColor
|
||||||
|
} else {
|
||||||
|
self.backgroundColor = UIColor.clear
|
||||||
|
}
|
||||||
|
|
||||||
|
configureProgressViewToBeCircular()
|
||||||
|
|
||||||
|
// set progress color
|
||||||
|
if let color = model.color {
|
||||||
|
setProgressColor = color.uiColor
|
||||||
|
} else {
|
||||||
|
setProgressColor = UIColor.red
|
||||||
|
}
|
||||||
|
|
||||||
|
// set track color
|
||||||
|
if let trackColor = model.trackColor {
|
||||||
|
setTrackColor = trackColor.uiColor
|
||||||
|
} else {
|
||||||
|
setProgressColor = UIColor.lightGray
|
||||||
|
}
|
||||||
|
|
||||||
|
// show circular progress view with animation.
|
||||||
|
showProgressWithAnimation(duration: 0.5, value: Float(graphModel?.percent ?? 0) / 100)
|
||||||
|
|
||||||
|
// show progress percentage label.
|
||||||
|
showProgressPercentage()
|
||||||
|
}
|
||||||
|
|
||||||
private func configureProgressViewToBeCircular() {
|
private func configureProgressViewToBeCircular() {
|
||||||
let lineWidth = graphModel?.lineWidth ?? 2.0
|
let lineWidth = graphModel?.lineWidth ?? 5.0
|
||||||
self.backgroundColor = UIColor.clear
|
|
||||||
|
|
||||||
self.drawShape(using: tracklayer, lineWidth: lineWidth)
|
self.drawShape(using: tracklayer, lineWidth: lineWidth)
|
||||||
self.drawShape(using: progressLayer, lineWidth: lineWidth)
|
self.drawShape(using: progressLayer, lineWidth: lineWidth)
|
||||||
@ -60,7 +104,8 @@ import UIKit
|
|||||||
self.layer.addSublayer(shape)
|
self.layer.addSublayer(shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setProgressWithAnimation(duration: TimeInterval, value: Float) {
|
// value range is [0,1]
|
||||||
|
private func showProgressWithAnimation(duration: TimeInterval, value: Float) {
|
||||||
let animation = CABasicAnimation(keyPath: "strokeEnd")
|
let animation = CABasicAnimation(keyPath: "strokeEnd")
|
||||||
animation.duration = duration
|
animation.duration = duration
|
||||||
|
|
||||||
@ -71,47 +116,26 @@ import UIKit
|
|||||||
progressLayer.add(animation, forKey: "animateCircle")
|
progressLayer.add(animation, forKey: "animateCircle")
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawLabel() {
|
private func showProgressPercentage() {
|
||||||
|
|
||||||
let percent = graphModel?.percent ?? 0
|
let percent = graphModel?.percent ?? 0
|
||||||
let percentLen = percent > 9 ? 2 : 1
|
let percentLen = percent > 9 ? 2 : 1
|
||||||
|
|
||||||
|
// configure attributed string for progress percentage.
|
||||||
let attributedString = NSMutableAttributedString(string: String(percent) + "%")
|
let attributedString = NSMutableAttributedString(string: String(percent) + "%")
|
||||||
|
// percent value
|
||||||
attributedString.setAttributes([NSAttributedString.Key.font: MFStyler.fontBoldTitleLarge()], range: NSMakeRange(0, percentLen))
|
attributedString.setAttributes([NSAttributedString.Key.font: MFStyler.fontBoldTitleLarge()], range: NSMakeRange(0, percentLen))
|
||||||
|
// % symbol
|
||||||
attributedString.setAttributes([NSAttributedString.Key.font: MFStyler.fontBoldBodyLarge()], range: NSMakeRange(percentLen, 1))
|
attributedString.setAttributes([NSAttributedString.Key.font: MFStyler.fontBoldBodyLarge()], range: NSMakeRange(percentLen, 1))
|
||||||
|
|
||||||
// Text layer
|
// show progress percentage in a text layer
|
||||||
let width = graphModel?.diameter ?? 84
|
let width = viewWidth
|
||||||
let height = width
|
let height = width
|
||||||
labelLayer.string = attributedString
|
labelLayer.string = attributedString
|
||||||
labelLayer.frame = CGRectMake((width - CGFloat(percentLen * 20))/2, (height - 30)/2, 60, 30)
|
labelLayer.frame = CGRectMake((width - CGFloat(percentLen * 20))/2, (height - 30)/2, 60, 30)
|
||||||
self.layer.addSublayer(labelLayer)
|
self.layer.addSublayer(labelLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: setup
|
|
||||||
open override func setupView() {
|
|
||||||
super.setupView()
|
|
||||||
heightConstraint = heightAnchor.constraint(equalToConstant: 0)
|
|
||||||
heightConstraint?.isActive = true
|
|
||||||
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
|
||||||
super.set(with: model, delegateObject, additionalData)
|
|
||||||
guard let model = model as? CircularProgressBarModel else { return }
|
|
||||||
|
|
||||||
configureProgressViewToBeCircular()
|
|
||||||
|
|
||||||
if let color = model.color {
|
|
||||||
setProgressColor = color.uiColor
|
|
||||||
}
|
|
||||||
|
|
||||||
if let backgroundColor = model.backgroundColor {
|
|
||||||
setTrackColor = backgroundColor.uiColor
|
|
||||||
}
|
|
||||||
|
|
||||||
setProgressWithAnimation(duration: 0.5, value: Float(graphModel?.percent ?? 0) / 100)
|
|
||||||
drawLabel()
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: MVMCoreUIViewConstrainingProtocol
|
//MARK: MVMCoreUIViewConstrainingProtocol
|
||||||
public func needsToBeConstrained() -> Bool {
|
public func needsToBeConstrained() -> Bool {
|
||||||
|
|||||||
@ -22,9 +22,10 @@ public class CircularProgressBarModel: MoleculeModelProtocol {
|
|||||||
public var diameter: CGFloat = 84
|
public var diameter: CGFloat = 84
|
||||||
public var lineWidth: CGFloat = 5
|
public var lineWidth: CGFloat = 5
|
||||||
public var color: Color?
|
public var color: Color?
|
||||||
public var backgroundColor: Color?
|
public var trackColor: Color?
|
||||||
public var percent: Int?
|
public var percent: Int?
|
||||||
|
public var backgroundColor: Color? = Color(uiColor: UIColor.clear)
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
updateSize()
|
updateSize()
|
||||||
}
|
}
|
||||||
@ -35,8 +36,9 @@ public class CircularProgressBarModel: MoleculeModelProtocol {
|
|||||||
case diameter
|
case diameter
|
||||||
case lineWidth
|
case lineWidth
|
||||||
case color
|
case color
|
||||||
case backgroundColor
|
case trackColor
|
||||||
case percent
|
case percent
|
||||||
|
case backgroundColor
|
||||||
case moleculeName
|
case moleculeName
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +60,10 @@ public class CircularProgressBarModel: MoleculeModelProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
color = try typeContainer.decodeIfPresent(Color.self, forKey: .color)
|
color = try typeContainer.decodeIfPresent(Color.self, forKey: .color)
|
||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
trackColor = try typeContainer.decodeIfPresent(Color.self, forKey: .trackColor)
|
||||||
percent = try typeContainer.decodeIfPresent(Int.self, forKey: .percent)
|
percent = try typeContainer.decodeIfPresent(Int.self, forKey: .percent)
|
||||||
|
|
||||||
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -69,9 +73,10 @@ public class CircularProgressBarModel: MoleculeModelProtocol {
|
|||||||
try container.encode(size, forKey: .size)
|
try container.encode(size, forKey: .size)
|
||||||
try container.encode(diameter, forKey: .diameter)
|
try container.encode(diameter, forKey: .diameter)
|
||||||
try container.encode(lineWidth, forKey: .lineWidth)
|
try container.encode(lineWidth, forKey: .lineWidth)
|
||||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
try container.encodeIfPresent(trackColor, forKey: .trackColor)
|
||||||
try container.encodeIfPresent(color, forKey: .color)
|
try container.encodeIfPresent(color, forKey: .color)
|
||||||
try container.encodeIfPresent(percent, forKey: .percent)
|
try container.encodeIfPresent(percent, forKey: .percent)
|
||||||
|
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCGColorsFromArray(_ colorArray: [String]) -> [Color] {
|
func getCGColorsFromArray(_ colorArray: [String]) -> [Color] {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user