CircularProgressView

刘玉石
2023-12-01
//
//  CircularProgressView.swift
//  CircularProgressView
//
//  Created by Chris Amanse on 5/2/15.
//  Copyright (c) 2015 Joe Christopher Paul Amanse. All rights reserved.
//

import UIKit

@IBDesignable
class CircularProgressView: UIView {
    // MARK: - Layers
    
    let trackLayer: CAShapeLayer = CAShapeLayer()
    let progressLayer: CAShapeLayer = CAShapeLayer()
    
    // MARK: - Properties
    
    @IBInspectable var trackWidth: CGFloat = 5.0 {
        didSet {
            redrawTrackSublayer()
            redrawProgressSublayer()
        }
    }
    
    @IBInspectable var trackColor: UIColor = UIColor.darkGrayColor() {
        didSet {
            trackLayer.strokeColor = trackColor.CGColor
        }
    }
    @IBInspectable var progressColor: UIColor = UIColor.lightGrayColor() {
        didSet {
            progressLayer.strokeColor = progressColor.CGColor
        }
    }
    @IBInspectable var progress: Double = 0 {
        didSet {
            redrawProgressSublayer()
        }
    }
    
    // MARK: - Drawing
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // Redraw layers to keep center and proportional
        redrawTrackSublayer()
        redrawProgressSublayer()
    }
    
    func redrawTrackSublayer() {
        let frameWidth = frame.width
        let frameHeight = frame.height
        let side: CGFloat = (frameWidth < frameHeight) ? frameWidth : frameHeight
        let trackCenter = CGPoint(x: frameWidth / 2, y: frameHeight / 2)
        
        let radius = (side - trackWidth) / 2
        let trackPath = UIBezierPath()
        trackPath.moveToPoint(CGPoint(x: trackCenter.x + radius, y: trackCenter.y))
        trackPath.addArcWithCenter(trackCenter, radius: radius, startAngle: 0, endAngle: CGFloat(2 * M_PI), clockwise: true)

        trackLayer.path = trackPath.CGPath
        trackLayer.lineWidth = trackWidth
    }
    
    func redrawProgressSublayer() {
        let frameWidth = frame.width
        let frameHeight = frame.height
        let side: CGFloat = (frameWidth < frameHeight) ? frameWidth : frameHeight
        let trackCenter = CGPoint(x: frameWidth / 2, y: frameHeight / 2)
        
        let radius = (side - trackWidth) / 2
        let progressPath = UIBezierPath()
        progressPath.moveToPoint(CGPoint(x: trackCenter.x, y: trackCenter.y - radius))
        progressPath.addArcWithCenter(trackCenter, radius: radius, startAngle: CGFloat(-M_PI_2), endAngle: CGFloat(progress*2*M_PI - M_PI_2), clockwise: true)
        
        progressLayer.path = progressPath.CGPath
        progressLayer.lineWidth = trackWidth
    }
    
    // MARK: - Initialization
    
    func commonInitialization() {
        // Add track layer
        trackLayer.opacity = 1
        trackLayer.strokeColor = trackColor.CGColor
        trackLayer.fillColor = nil
        layer.addSublayer(trackLayer)
        
        // Add progress layer
        progressLayer.opacity = 1
        progressLayer.strokeColor = progressColor.CGColor
        progressLayer.fillColor = nil
        layer.addSublayer(progressLayer)
    }
    
    // MARK: Live Render IB
    override func prepareForInterfaceBuilder() {
        commonInitialization()
    }
    
    // MARK: IB load
    override func awakeFromNib() {
        commonInitialization()
    }
    
    // MARK: Programmatic
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        // Initialize sublayers
        commonInitialization()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    convenience init(frame: CGRect, trackWidth: CGFloat, progress: Double) {
        self.init(frame: frame)
        self.trackWidth = trackWidth
        self.progress = progress
    }
}


相关阅读

相关文章

相关问答