封裝了一個UILabel並讓它顯示圓形的邊框,UILabel上面顯示百份比,而邊框則用Animation繪製到整個圓佔指定百分比的點。ide
這只是我我的想的繼承一個UILabel實現的,用到兩個CAShapeLayer,第一個Layer的做用是畫出灰色的背影圓圈,第二個Layer位置放置在第一個Layer的上面,並設置爲紅色描繪顏色並描繪到插定的位置,以後實現相應的動畫效果便可。動畫
import UIKit class kCircleLabel: UILabel { var percent:Double! convenience init(percent per:Double,frame:CGRect) { self.init(frame: frame) self.percent = per createCircle() } override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } func createCircle() { self.textAlignment = NSTextAlignment.Center self.text = "\(percent * 100 )%" //第一個圓形Layer,邊框爲灰色的 let circleLayer:CAShapeLayer = CAShapeLayer() circleLayer.lineWidth = 8 //清除填充的顏色 circleLayer.fillColor = UIColor.clearColor().CGColor //邊框的顏色 circleLayer.strokeColor = UIColor.init(red: CGFloat(220.0 / 255.0 ), green: CGFloat(220.0 / 255.0), blue: CGFloat(220.0 / 255.0), alpha: 1.0).CGColor //用貝塞爾曲線畫出一個圓 let circlePath:UIBezierPath = UIBezierPath(ovalInRect: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)) circleLayer.path = circlePath.CGPath self.layer.addSublayer(circleLayer) //第二個只描繪到特定位置的弧Layer let arcLayer:CAShapeLayer = CAShapeLayer() //畫出特定的弧 let arcPath:UIBezierPath = UIBezierPath(arcCenter: CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2), radius: self.frame.size.width / 2, startAngle: 0.0, endAngle: CGFloat(360 * percent / 180 * M_PI), clockwise: true) arcLayer.path = arcPath.CGPath arcLayer.lineWidth = 8 //清除填充的顏色 arcLayer.fillColor = UIColor.clearColor().CGColor arcLayer.strokeColor = UIColor.redColor().CGColor //弧Layer的動畫 let arcAnimation:CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd") arcAnimation.fromValue = 0.0 arcAnimation.toValue = 1.0 arcAnimation.duration = 1.5 arcAnimation.removedOnCompletion = false arcAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) //這是從大到小的動畫,適用於整個Layer let scaleAnimation:CABasicAnimation = CABasicAnimation(keyPath: "transform.scale") scaleAnimation.fromValue = 5.0 scaleAnimation.toValue = 1.0 scaleAnimation.duration = 0.5 arcLayer.addAnimation(arcAnimation, forKey: nil) /*let animationGroup:CAAnimationGroup = CAAnimationGroup() animationGroup.duration = 1.0 animationGroup.animations = [ arcAnimation, scaleAnimation]*/ self.layer.insertSublayer(arcLayer, above : circleLayer) self.layer.addAnimation(scaleAnimation, forKey: nil) } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. //override func drawRect(rect: CGRect) { // Drawing code //} }
調用時:ui
let circleLabel = kCircleLabel(percent: 0.52, frame: CGRect(x: (self.view.bounds.width - 100.0) / 2, y: 260, width: 100.0, height: 100.0))code
self.view.addSubview(circleLabel)orm
要實現這個效果的關鍵是要學會怎麼使用貝塞爾曲線,並給Layer設置Path。blog