你好,歡迎來到IOS教程網

 Ios教程網 >> IOS使用技巧 >> IOS7技巧 >> Swift 制作一個帶動畫效果的環形進度條例子

Swift 制作一個帶動畫效果的環形進度條例子

編輯:IOS7技巧
本文章來為各位介紹一個關於Swift - 制作一個帶動畫效果的環形進度條了,希望這個例子能夠為大家帶來幫助的哦,具體如下所示。

1,帶動畫效果的環形進度條

下面我們演示如何制作一個環狀進度條組件,當進度改變時,進度條長度變化時是有動畫效果的(我們還可以設置動畫時間,或者關閉動畫),效果圖如下:


(1)動畫實現原理

使用 Core Animation 動畫根據進度改變進度條(CAShapeLayer)的 strokeEnd。

(2)組件代碼(OProgressView.swift)


import UIKit
 
@IBDesignable class OProgressView: UIView {
    
    struct Constant {
        //進度條寬度
        static let lineWidth: CGFloat = 10
        //進度槽顏色
        static let trackColor = UIColor(red: 245/255.0, green: 245/255.0, blue: 245/255.0,
            alpha: 1)
        //進度條顏色
        static let progressColoar = UIColor.orangeColor()
    }
    
    //進度槽
    let trackLayer = CAShapeLayer()
    //進度條
    let progressLayer = CAShapeLayer()
    //進度條路徑(整個圓圈)
    let path = UIBezierPath()
    
    //當前進度
    @IBInspectable var progress: Int = 0 {
        didSet {
            if progress > 100 {
                progress = 100
            }else if progress < 0 {
                progress = 0
            }
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    override func drawRect(rect: CGRect) {
        //獲取整個進度條圓圈路徑
        path.addArcWithCenter(CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)),
            radius: bounds.size.width/2 - Constant.lineWidth,
            startAngle: angleToRadian(-90), endAngle: angleToRadian(270), clockwise: true)
        
        //繪制進度槽
        trackLayer.frame = bounds
        trackLayer.fillColor = UIColor.clearColor().CGColor
        trackLayer.strokeColor = Constant.trackColor.CGColor
        trackLayer.lineWidth = Constant.lineWidth
        trackLayer.path = path.CGPath
        layer.addSublayer(trackLayer)
        
        //繪制進度條
        progressLayer.frame = bounds
        progressLayer.fillColor = UIColor.clearColor().CGColor
        progressLayer.strokeColor = Constant.progressColoar.CGColor
        progressLayer.lineWidth = Constant.lineWidth
        progressLayer.path = path.CGPath
        progressLayer.strokeStart = 0
        progressLayer.strokeEnd = CGFloat(progress)/100.0
        layer.addSublayer(progressLayer)
    }
    
    //設置進度(可以設置是否播放動畫)
    func setProgress(pro: Int,animated anim: Bool) {
        setProgress(pro, animated: anim, withDuration: 0.55)
    }
    
    //設置進度(可以設置是否播放動畫,以及動畫時間)
    func setProgress(pro: Int,animated anim: Bool, withDuration duration: Double) {
        progress = pro
        //進度條動畫
        CATransaction.begin()
        CATransaction.setDisableActions(!anim)
        CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
            kCAMediaTimingFunctionEaseInEaseOut))
        CATransaction.setAnimationDuration(duration)
        progressLayer.strokeEnd = CGFloat(progress)/100.0
        CATransaction.commit()
    }
    
    //將角度轉為弧度
    private func angleToRadian(angle: Double)->CGFloat {
        return CGFloat(angle/Double(180.0) * M_PI)
    }
}

2,進度條頭部增加圓點
下面給進度條頭部增加一個帶陰影的圓點,其隨著進度條的增長也會動態地移動位置。
原文:Swift - 制作一個帶動畫效果的環形進度條

(1)實現原理

使用關鍵幀動畫(CAKeyframeAnimation)讓圓點順著圓弧路徑移動。

(2)組件代碼(OProgressView2.swift)


import UIKit
 
@IBDesignable class OProgressView2: UIView {
    
    struct Constant {
        //進度條寬度
        static let lineWidth: CGFloat = 10
        //進度槽顏色
        static let trackColor = UIColor(red: 245/255.0, green: 245/255.0, blue: 245/255.0,
            alpha: 1)
        //進度條顏色
        static let progressColoar = UIColor.orangeColor()
    }
    
    //進度槽
    let trackLayer = CAShapeLayer()
    //進度條
    let progressLayer = CAShapeLayer()
    //進度條路徑(整個圓圈)
    let path = UIBezierPath()  
    //頭部圓點
    var dot:UIView!
    
    //進度條圓環中點
    var progressCenter:CGPoint {
        get{
            return CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))
        }
    }
    
    //進度條圓環中點
    var radius:CGFloat{
        get{
            return bounds.size.width/2 - Constant.lineWidth
        }
    }
    
    //當前進度
    @IBInspectable var progress: Int = 0 {
        didSet {
            if progress > 100 {
                progress = 100
            }else if progress < 0 {
                progress = 0
            }
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    override func drawRect(rect: CGRect) {
        //獲取整個進度條圓圈路徑
        path.addArcWithCenter(progressCenter, radius: radius,
            startAngle: angleToRadian(-90), endAngle: angleToRadian(270), clockwise: true)
        
        //繪制進度槽
        trackLayer.frame = bounds
        trackLayer.fillColor = UIColor.clearColor().CGColor
        trackLayer.strokeColor = Constant.trackColor.CGColor
        trackLayer.lineWidth = Constant.lineWidth
        trackLayer.path = path.CGPath
        layer.addSublayer(trackLayer)
        
        //繪制進度條
        progressLayer.frame = bounds
        progressLayer.fillColor = UIColor.clearColor().CGColor
        progressLayer.strokeColor = Constant.progressColoar.CGColor
        progressLayer.lineWidth = Constant.lineWidth
        progressLayer.path = path.CGPath
        progressLayer.strokeStart = 0
        progressLayer.strokeEnd = CGFloat(progress)/100.0
        layer.addSublayer(progressLayer)
        
        //繪制進度條頭部圓點
        dot = UIView(frame:CGRectMake(0, 0, Constant.lineWidth, Constant.lineWidth))
        let dotPath = UIBezierPath(ovalInRect:
            CGRectMake(0,0, Constant.lineWidth, Constant.lineWidth)).CGPath
        let arc = CAShapeLayer()
        arc.lineWidth = 0
        arc.path = dotPath
        arc.strokeStart = 0
        arc.strokeEnd = 1
        arc.strokeColor = Constant.progressColoar.CGColor
        arc.fillColor = Constant.progressColoar.CGColor
        arc.shadowColor = UIColor.blackColor().CGColor
        arc.shadowRadius = 5.0
        arc.shadowOpacity = 0.5
        arc.shadowOffset = CGSizeZero
        dot.layer.addSublayer(arc)
        dot.layer.position = calcCircleCoordinateWithCenter(progressCenter,
            radius: radius, angle: CGFloat(-progress)/100*360+90)
        addSubview(dot)
    }
    
    //設置進度(可以設置是否播放動畫)
    func setProgress(pro: Int,animated anim: Bool) {
        setProgress(pro, animated: anim, withDuration: 0.55)
    }
    
    //設置進度(可以設置是否播放動畫,以及動畫時間)
    func setProgress(pro: Int,animated anim: Bool, withDuration duration: Double) {
        let oldProgress = progress
        progress = pro
        
        //進度條動畫
        CATransaction.begin()
        CATransaction.setDisableActions(!anim)
        CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
            kCAMediaTimingFunctionEaseInEaseOut))
        CATransaction.setAnimationDuration(duration)
        progressLayer.strokeEnd = CGFloat(progress)/100.0
        CATransaction.commit()
        
        //頭部圓點動畫
        let startAngle = angleToRadian(360*Double(oldProgress)/100 - 90)
        let endAngle = angleToRadian(360*Double(progress)/100 - 90)
        let clockWise = progress > oldProgress ? false : true
        let path2 = CGPathCreateMutable()
        CGPathAddArc(path2, &transform, CGRectGetMidX(bounds), CGRectGetMidY(bounds),
            bounds.size.width/2 - Constant.lineWidth,
            startAngle, endAngle, clockWise)
        
        let orbit = CAKeyframeAnimation(keyPath:"position")
        orbit.duration = duration
        orbit.path = path2
        orbit.calculationMode = kCAAnimationPaced
        orbit.timingFunction =
            CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        orbit.removedOnCompletion = false
        orbit.fillMode = kCAFillModeForwards
        dot.layer.addAnimation(orbit,forKey:"Move")
    }
    
    //將角度轉為弧度
    private func angleToRadian(angle: Double)->CGFloat {
        return CGFloat(angle/Double(180.0) * M_PI)
    }
    
    //計算圓弧上點的坐標
    func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
        -> CGPoint {
            let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)))
            let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)))
            return CGPointMake(center.x+x2, center.y-y2);
    }
}

3,進度條頭部再增加一個圖片

下面給進度條頭部再增加一個前進圖標,其隨著進度條的增長也會動態地改變朝向(一直朝向前進方向)。
原文:Swift - 制作一個帶動畫效果的環形進度條

(1)實現原理

箭頭圖標在最開始位置時,默認方向向右。同時將 CAKeyframeAnimation 的 rotationMode 設為 kCAAnimationRotateAuto,這樣隨著進度改變,箭頭會始終朝著前進方向。


(2)組件代碼(OProgressView3.swift)


import UIKit
 
@IBDesignable class OProgressView3: UIView {
    
    struct Constant {
        //進度條寬度
        static let lineWidth: CGFloat = 10
        //進度槽顏色
        static let trackColor = UIColor(red: 245/255.0, green: 245/255.0, blue: 245/255.0,
            alpha: 1)
        //進度條顏色
        static let progressColoar = UIColor.orangeColor()
    }
    
    //進度槽
    let trackLayer = CAShapeLayer()
    //進度條
    let progressLayer = CAShapeLayer()
    //進度條路徑(整個圓圈)
    let path = UIBezierPath()
    //頭部圓點
    var dot = UIView()
    //頭部箭頭圖片
    var arrow = UIImageView(image: UIImage(named: "arrow"))
    
    //進度條圓環中點
    var progressCenter:CGPoint {
        get{
            return CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))
        }
    }
    
    //進度條圓環中點
    var radius:CGFloat{
        get{
            return bounds.size.width/2 - Constant.lineWidth
        }
    }
    
    //當前進度
    @IBInspectable var progress: Int = 0 {
        didSet {
            if progress > 100 {
                progress = 100
            }else if progress < 0 {
                progress = 0
            }
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    override func drawRect(rect: CGRect) {
        //獲取整個進度條圓圈路徑
        path.addArcWithCenter(progressCenter, radius: radius,
            startAngle: angleToRadian(-90), endAngle: angleToRadian(270), clockwise: true)
        
        //繪制進度槽
        trackLayer.frame = bounds
        trackLayer.fillColor = UIColor.clearColor().CGColor
        trackLayer.strokeColor = Constant.trackColor.CGColor
        trackLayer.lineWidth = Constant.lineWidth
        trackLayer.path = path.CGPath
        layer.addSublayer(trackLayer)
        
        //繪制進度條
        progressLayer.frame = bounds
        progressLayer.fillColor = UIColor.clearColor().CGColor
        progressLayer.strokeColor = Constant.progressColoar.CGColor
        progressLayer.lineWidth = Constant.lineWidth
        progressLayer.path = path.CGPath
        progressLayer.strokeStart = 0
        progressLayer.strokeEnd = CGFloat(progress)/100.0
        layer.addSublayer(progressLayer)
        
        //繪制進度條頭部圓點
        dot.frame = CGRectMake(0, 0, Constant.lineWidth, Constant.lineWidth)
        let dotPath = UIBezierPath(ovalInRect:
            CGRectMake(0,0, Constant.lineWidth, Constant.lineWidth)).CGPath
        let arc = CAShapeLayer()
        arc.lineWidth = 0
        arc.path = dotPath
        arc.strokeStart = 0
        arc.strokeEnd = 1
        arc.strokeColor = Constant.progressColoar.CGColor
        arc.fillColor = Constant.progressColoar.CGColor
        arc.shadowColor = UIColor.blackColor().CGColor
        arc.shadowRadius = 5.0
        arc.shadowOpacity = 0.5
        arc.shadowOffset = CGSizeZero
        dot.layer.addSublayer(arc)
        addSubview(dot)
        
        //圓點中添加箭頭圖標
        arrow.frame.size = CGSize(width: Constant.lineWidth, height: Constant.lineWidth)
        dot.addSubview(arrow)
        
        //設置圓點位置
        dot.layer.position = calcCircleCoordinateWithCenter(progressCenter,
            radius: radius, angle: CGFloat(-progress)/100*360+90)
    }
    
    //設置進度(可以設置是否播放動畫)
    func setProgress(pro: Int,animated anim: Bool) {
        setProgress(pro, animated: anim, withDuration: 0.55)
    }
    
    //設置進度(可以設置是否播放動畫,以及動畫時間)
    func setProgress(pro: Int,animated anim: Bool, withDuration duration: Double) {
        let oldProgress = progress
        progress = pro
        
        //進度條動畫
        CATransaction.begin()
        CATransaction.setDisableActions(!anim)
        CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
            kCAMediaTimingFunctionEaseInEaseOut))
        CATransaction.setAnimationDuration(duration)
        progressLayer.strokeEnd = CGFloat(progress)/100.0
        CATransaction.commit()
        
        //頭部圓點動畫
        let startAngle = angleToRadian(360*Double(oldProgress)/100 - 90)
        let endAngle = angleToRadian(360*Double(progress)/100 - 90)
        let clockWise = progress > oldProgress ? false : true
        let path2 = CGPathCreateMutable()
        CGPathAddArc(path2, &transform, CGRectGetMidX(bounds), CGRectGetMidY(bounds),
            bounds.size.width/2 - Constant.lineWidth,
            startAngle, endAngle, clockWise)
        
        let orbit = CAKeyframeAnimation(keyPath:"position")
        orbit.duration = duration
        orbit.path = path2
        orbit.calculationMode = kCAAnimationPaced
        orbit.timingFunction =
            CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        orbit.rotationMode = kCAAnimationRotateAuto
        orbit.removedOnCompletion = false
        orbit.fillMode = kCAFillModeForwards
        dot.layer.addAnimation(orbit,forKey:"Move")
    }
    
    //將角度轉為弧度
    private func angleToRadian(angle: Double)->CGFloat {
        return CGFloat(angle/Double(180.0) * M_PI)
    }
    
    //計算圓弧上點的坐標
    func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
        -> CGPoint {
            let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)))
            let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)))
            return CGPointMake(center.x+x2, center.y-y2);
    }
}

4,測試代碼


import UIKit
 
class ViewController: UIViewController {
    
    @IBOutlet weak var oProgressView1: OProgressView!
    @IBOutlet weak var oProgressView2: OProgressView2!
    @IBOutlet weak var oProgressView3: OProgressView3!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    //增加進度
    @IBAction func addProgress(sender: AnyObject) {
        oProgressView1.setProgress(oProgressView1.progress + 25, animated: true)
        oProgressView2.setProgress(oProgressView2.progress + 25, animated: true)
        oProgressView3.setProgress(oProgressView3.progress + 25, animated: true)
    }
    
    //減少進度
    @IBAction func minusProgress(sender: AnyObject) {
        oProgressView1.setProgress(oProgressView1.progress - 20, animated: true)
        oProgressView2.setProgress(oProgressView2.progress - 20, animated: true)
        oProgressView3.setProgress(oProgressView3.progress - 20, animated: true)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

原文出自:www.hangge.com 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved