Swift

Swift - EasingAnimation绘制圆环动画

效果

源码

https://github.com/YouXianMing/Swift-Animations

//
//  CircleView.swift
//  Swift-Animations
//
//  Created by YouXianMing on 16/8/16.
//  Copyright © 2016年 YouXianMing. All rights reserved.
//

import UIKit

// MARK: Public class : CircleView

class CircleView: UIView {
    
    // MARK: Convenience init.
    
    convenience init(frame: CGRect, lineWidth : CGFloat, lineColor : UIColor, clockWise : Bool, startDegree : CGFloat) {
        
        self.init(frame : frame)
        self.lineWidth   = lineWidth
        self.lineColor   = lineColor
        self.clockWise   = clockWise
        self.startDegree = startDegree
        self.makeEffective()
    }
    
    // MARK: Properties.
    
    /// Line width, default is 1.0.
    var lineWidth    : CGFloat {
        
        get { if pLineWidth <= 0 { return 1} else {return pLineWidth}}
        set(newVal) { pLineWidth = newVal}
    }
    
    /// Line color, default is black color.
    var lineColor    : UIColor {
    
        get { if pLineColor == nil { return UIColor.blackColor()} else {return pLineColor}}
        set(newVal) { pLineColor = newVal}
    }
    
    /// Clock wise or not, default is true.
    var clockWise    : Bool    = true
    
    /// Start degrees (0° ~ 360°), default is 0.
    var startDegree  : CGFloat = 0
    
    // MARK: Methods.
    
    /**
     Make the config effective, when you set all the properties, you must run this method to make the config effective.
     */
    func makeEffective() {
        
        let size   = bounds.size
        let radius = size.width / 2.0 - lineWidth / 2.0
        
        var tmpStartAngle : CGFloat
        var tmpEndAngle   : CGFloat
        
        if clockWise == true {
            
            tmpStartAngle = -radianFromDegrees(180 - startDegree)
            tmpEndAngle   = radianFromDegrees(180 + startDegree)
            
        } else {
        
            tmpStartAngle = radianFromDegrees(180 - startDegree)
            tmpEndAngle   = -radianFromDegrees(180 + startDegree)
        }
        
        let circlePath           = UIBezierPath(arcCenter: CGPointMake(size.height / 2, size.width / 2),
                                                radius: radius, startAngle: tmpStartAngle, endAngle: tmpEndAngle, clockwise: clockWise)
        pCircleLayer.path        = circlePath.CGPath
        pCircleLayer.fillColor   = UIColor.clearColor().CGColor
        pCircleLayer.strokeColor = lineColor.CGColor
        pCircleLayer.lineWidth   = lineWidth
        pCircleLayer.strokeEnd   = 0
    }
    
    /**
     Stroke start animation.
     
     - parameter value:          StrokeStart value, range is [0, 1].
     - parameter easingFunction: Easing function enum value.
     - parameter animated:       Animated or not.
     - parameter duration:       The animation's duration.
     */
    func strokeStart(value : Double, easingFunction : EasingFunction, animated : Bool, duration : NSTimeInterval) {
        
        var strokeStartValue = value
        
        if strokeStartValue <= 0 {
            
            strokeStartValue = 0
            
        } else if strokeStartValue >= 1 {
        
            strokeStartValue = 1
        }
        
        if animated == true {
            
            let easingValue          = EasingValue(withFunction: easingFunction, frameCount: Int(duration * 60.0))
            let keyAnimation         = CAKeyframeAnimation(keyPath: "strokeStart")
            keyAnimation.duration    = duration
            keyAnimation.values      = easingValue.frameValueWith(fromValue: Double(pCircleLayer.strokeStart), toValue: strokeStartValue)
            
            pCircleLayer.strokeStart = CGFloat(strokeStartValue)
            pCircleLayer.addAnimation(keyAnimation, forKey: nil)
            
        } else {
        
            CATransaction.setDisableActions(true)
            pCircleLayer.strokeStart = CGFloat(strokeStartValue)
            CATransaction.setDisableActions(false)
        }
    }
    
    /**
     Stroke end animation.
     
     - parameter value:          StrokeEnd value, range is [0, 1].
     - parameter easingFunction: Easing function enum value.
     - parameter animated:       Animated or not.
     - parameter duration:       The animation's duration.
     */
    func strokeEnd(value : Double, easingFunction : EasingFunction, animated : Bool, duration : NSTimeInterval) {
        
        var strokeStartValue = value
        
        if strokeStartValue <= 0 {
            
            strokeStartValue = 0
            
        } else if strokeStartValue >= 1 {
            
            strokeStartValue = 1
        }
        
        if animated == true {
            
            let easingValue        = EasingValue(withFunction: easingFunction, frameCount: Int(duration * 60.0))
            let keyAnimation       = CAKeyframeAnimation(keyPath: "strokeEnd")
            keyAnimation.duration  = duration
            keyAnimation.values    = easingValue.frameValueWith(fromValue: Double(pCircleLayer.strokeEnd), toValue: strokeStartValue)
            
            pCircleLayer.strokeEnd = CGFloat(strokeStartValue)
            pCircleLayer.addAnimation(keyAnimation, forKey: nil)
            
        } else {
            
            CATransaction.setDisableActions(true)
            pCircleLayer.strokeEnd = CGFloat(strokeStartValue)
            CATransaction.setDisableActions(false)
        }
    }
    
    // MARK: Private value & func & system method.
    
    override init(frame: CGRect) {
        
        super.init(frame: frame)
        pCircleLayer       = CAShapeLayer()
        pCircleLayer.frame = bounds
        layer.addSublayer(pCircleLayer)
    }
    
    required init?(coder aDecoder: NSCoder) {
        
        fatalError("init(coder:) has not been implemented")
    }
    
    private var pCircleLayer : CAShapeLayer!
    private var pLineWidth   : CGFloat! = 1
    private var pLineColor   : UIColor! = UIColor.blackColor()
    
    private func radianFromDegrees(degrees : CGFloat) -> CGFloat {
    
        return (CGFloat(M_PI) * degrees) / 180.0
    }
}
原文地址:https://www.cnblogs.com/YouXianMing/p/5778079.html