SHARE
TWEET

Untitled

a guest May 26th, 2019 94 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. //  CircularProgressView
  3. //  
  4. //
  5. //  Created by KuroiDOC on 16/05/19.
  6. //  Copyright © 2019 KuroiDOC. All rights reserved.
  7. //
  8.  
  9. class CircularProgressView : UIView {
  10.     var title : NSAttributedString? {
  11.         didSet { setNeedsLayout() }
  12.     }
  13.    
  14.     var progress : CGFloat = 0 {
  15.         didSet { setNeedsLayout() }
  16.     }
  17.    
  18.     var progressTintColor : UIColor = .red {
  19.         didSet { setNeedsLayout() }
  20.     }
  21.    
  22.     var trackTintColor : UIColor = .gray {
  23.         didSet { setNeedsLayout() }
  24.     }
  25.    
  26.     var leftText : NSAttributedString? {
  27.         didSet { setNeedsLayout() }
  28.     }
  29.    
  30.     var rightText : NSAttributedString? {
  31.         didSet { setNeedsLayout() }
  32.     }
  33.    
  34.     func degsToRads(_ degrees: CGFloat) -> CGFloat {
  35.         return degrees * CGFloat.pi / 180
  36.     }
  37.    
  38.     override func layoutSubviews() {
  39.         layer.sublayers?.forEach { $0.removeFromSuperlayer() }
  40.         super.layoutSubviews()
  41.         setupLayers()
  42.     }
  43.    
  44.     private func setupLayers() {
  45.         let rect = self.bounds
  46.         let center = CGPoint(x: rect.origin.x + rect.size.width / 2,
  47.                              y: rect.origin.y + rect.size.height / 2)
  48.         let radius = rect.size.height * 0.4
  49.         let trackPath = CGMutablePath()
  50.         trackPath.addArc(center: center, radius: radius, startAngle: degsToRads(130), endAngle: degsToRads(50), clockwise: false)
  51.        
  52.         let trackLayer = CAShapeLayer()
  53.         trackLayer.name = "Track"
  54.         trackLayer.anchorPoint = .zero
  55.         trackLayer.path = trackPath
  56.         trackLayer.bounds = rect
  57.         trackLayer.lineCap = .round
  58.         trackLayer.strokeColor = trackTintColor.cgColor
  59.         trackLayer.fillColor = backgroundColor?.cgColor
  60.         trackLayer.lineWidth = 10
  61.         trackLayer.allowsGroupOpacity = true
  62.         trackLayer.fillMode = .forwards
  63.         layer.addSublayer(trackLayer)
  64.        
  65.         let progress = self.progress > 1 ? 1 : self.progress
  66.         let progressPath = CGMutablePath()
  67.         progressPath.addRelativeArc(center: center, radius: radius, startAngle: degsToRads(130), delta: degsToRads(280 * progress), transform: .identity)
  68.        
  69.         let progressLayer = CAShapeLayer()
  70.         progressLayer.name = "Progress"
  71.         progressLayer.anchorPoint = .zero
  72.         progressLayer.path = progressPath
  73.         progressLayer.bounds = rect
  74.         progressLayer.lineCap = .round
  75.         progressLayer.strokeColor = progressTintColor.cgColor
  76.         progressLayer.fillColor = UIColor.clear.cgColor
  77.         progressLayer.lineWidth = 10
  78.         progressLayer.allowsGroupOpacity = true
  79.         progressLayer.fillMode = .forwards
  80.         progressLayer.strokeEnd = 0
  81.        
  82.         let strokeEndAnimation = CABasicAnimation()
  83.         strokeEndAnimation.beginTime = self.layer.convertTime(CACurrentMediaTime(), from: nil) + 0.000001
  84.         strokeEndAnimation.duration = 2
  85.         strokeEndAnimation.fillMode = .forwards
  86.         strokeEndAnimation.isRemovedOnCompletion = false
  87.         strokeEndAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
  88.         strokeEndAnimation.keyPath = "strokeEnd"
  89.         strokeEndAnimation.toValue = 1
  90.         strokeEndAnimation.fromValue = 0
  91.        
  92.         progressLayer.add(strokeEndAnimation, forKey: "strokeEndAnimation")
  93.         layer.addSublayer(progressLayer)
  94.        
  95.         if let title = title {
  96.             let titleBoundingRect = title.boundingRect(with: CGSize(width: rect.width * 0.4, height: .greatestFiniteMagnitude),
  97.                                                        options: [.usesFontLeading, .usesLineFragmentOrigin],
  98.                                                        context: nil)
  99.             let titleLayer = CATextLayer()
  100.             titleLayer.string = title
  101.             titleLayer.position = rect.center
  102.             titleLayer.bounds = titleBoundingRect
  103.             titleLayer.alignmentMode = .center
  104.             layer.addSublayer(titleLayer)
  105.         }
  106.        
  107.         if let leftText = self.leftText {
  108.             var leftTextPoint = point(at: radius, angle: degsToRads(130), from: center)
  109.             leftTextPoint.x += 4
  110.             let leftTextLayer = CATextLayer()
  111.             leftTextLayer.string = leftText
  112.             leftTextLayer.position = rect.center
  113.             leftTextLayer.frame = CGRect(origin: leftTextPoint, size: leftText.size())
  114.             leftTextLayer.alignmentMode = .center
  115.             layer.addSublayer(leftTextLayer)
  116.         }
  117.        
  118.         if let rightText = self.rightText {
  119.             var rightTextPoint = point(at: radius, angle: degsToRads(50), from: center)
  120.             rightTextPoint.x -= rightText.size().width + 4
  121.             let rightTextLayer = CATextLayer()
  122.             rightTextLayer.string = rightText
  123.             rightTextLayer.position = rect.center
  124.             rightTextLayer.frame = CGRect(origin: rightTextPoint, size: rightText.size())
  125.             rightTextLayer.alignmentMode = .center
  126.             layer.addSublayer(rightTextLayer)
  127.         }
  128.     }
  129.    
  130.     func point(at radius: CGFloat, angle: CGFloat, from: CGPoint) -> CGPoint {
  131.         return CGPoint(x: from.x + radius * cos(angle),
  132.                        y: from.y + radius * sin(angle))
  133.     }
  134. }
  135.  
  136. extension CGPoint {
  137.     static func / (left: CGPoint, right: CGFloat) -> CGPoint {
  138.         return CGPoint(x: left.x / right, y: left.y / right)
  139.     }
  140. }
  141.  
  142. extension CGRect {
  143.     var center : CGPoint {
  144.         return CGPoint(x: self.origin.x + self.width / 2, y: self.origin.y + self.height / 2)
  145.     }
  146.    
  147.     init(center: CGPoint, size: CGSize) {
  148.         let origin = CGPoint(x: center.x - size.width / 2, y: center.y - size.height / 2)
  149.         self.init(origin: origin, size: size)
  150.     }
  151. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top