今天看了一個例子,按照自己的思路用swift寫了一個,跟大家分享下。執行完的結果如下(剛開始不知道怎麼傳動態圖 - -!):
這個實現的效果是 每點擊一下屏幕,就會出現一段隨機顏色的圓環接着之前的圓環旋轉
實現代碼:
1.新建swift文件,繼承於UIView,內容如下:
import UIKit
class CustomProgessView: UIView {
}
2.聲明:聲明所有的全局變量
//圓環線寬
let lineWidth = 50.0
//整個圓環完成所需時間
let duration:CGFloat = 5.0
//圓環是否全部完成
var circleComplete = false
//背景灰色圓環
var backgroundLayer: CAShapeLayer!
//所有圓環段的集合
var layerArray: [CAShapeLayer]!
override init(frame: CGRect) {
super.init(frame: frame)
initParam()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initParam()
}
func initParam() {
layerArray = Array()
addBackgroundCircle()
}
func addBackgroundCircle() {
backgroundLayer = CAShapeLayer()
backgroundLayer.fillColor = UIColor.clearColor().CGColor
backgroundLayer.strokeColor = UIColor.grayColor().CGColor
backgroundLayer.lineWidth = CGFloat(lineWidth)
layer.addSublayer(backgroundLayer)
var backgroundPath = UIBezierPath(ovalInRect: self.bounds)
backgroundLayer.path = backgroundPath.CGPath
}
4.生成一段圓環CAShapeLayer 函數
func randomColor() -> UIColor {
var h = CGFloat(Double(arc4random() % 256) / 256.0)
var s = CGFloat(Double(arc4random() % 128) / 256.0) + 0.5
var b = CGFloat(Double(arc4random() % 128) / 256.0) + 0.5
return UIColor(hue: h, saturation: s, brightness: b, alpha: 1.0)
}
func createOneLayer(){
var progessLayer = CAShapeLayer()
progessLayer.fillColor = UIColor.clearColor().CGColor
progessLayer.strokeColor = randomColor().CGColor
progessLayer.lineWidth = backgroundLayer.lineWidth
progessLayer.strokeStart = 0.0
progessLayer.strokeEnd = 0.0
progessLayer.path = backgroundLayer.path
layer.addSublayer(progessLayer)
layerArray.append(progessLayer)
}
5.開啓觸摸函數,每點擊一下屏幕就要生成一個圓環
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if circleComplete == false{
createOneLayer()
showLayerAnimation()
}
}
6.顯示每一個圓環的動畫,
重點來了,這裏因爲不但要同時顯示Layer動畫,還要同時清除圓環的舊Layer,用到keyPath="strokeStart"和keyPath="strokeEnd"
/*
1 keyPath = strokeStart 動畫的fromValue = 0,toValue = 1
表示從路徑的0位置畫到1 怎麼畫是按照清除開始的位置也就是清除0 一直清除到1 效果就是一條路徑慢慢的消失
2 keyPath = strokeStart 動畫的fromValue = 1,toValue = 0
表示從路徑的1位置畫到0 怎麼畫是按照清除開始的位置也就是1 這樣開始的路徑是空的(即都被清除掉了)一直清除到0 效果就是一條路徑被反方向畫出來
3 keyPath = strokeEnd 動畫的fromValue = 0,toValue = 1
表示 這裏我們分3個點說明動畫的順序 strokeEnd從結尾開始清除 首先整條路徑先清除後2/3,接着清除1/3 效果就是正方向畫出路徑
4 keyPath = strokeEnd 動畫的fromValue = 1,toValue = 0
效果就是反方向路徑慢慢消失
*/
要點:
(1)新添加的那個圓環因爲fromValue是從0.0開始,所以不需要清除。其他的所有圓環,做繼續做toValue=1.0的同時,還需要同時清除從strokeStart到strokeEnd的舊Layer。
(2)同時還要注意每添加一個圓環段,都需要重新計算剩下動畫進度的時間
func showLayerAnimation(){
for oneProgessLayer in layerArray {
//動畫時間爲剩餘路徑的動畫時間
let leftAnimationDuration = duration * (1.0 - oneProgessLayer.strokeEnd)
//公共動畫 fromValue是上一次的toValue,toValue都爲1
var commonAnimation = CABasicAnimation(keyPath: "strokeEnd")
commonAnimation.duration = NSTimeInterval(leftAnimationDuration)
commonAnimation.fromValue = oneProgessLayer.strokeEnd
commonAnimation.toValue = 1.0
commonAnimation.fillMode = kCAFillModeForwards
commonAnimation.removedOnCompletion = false
oneProgessLayer.addAnimation(commonAnimation, forKey: "strokeEnd")
//除了最新添加的那個Layer,其他都需要清除舊的Layer
if layerArray.last !== oneProgessLayer {
var dissaperAnimation = CABasicAnimation(keyPath: "strokeStart")
dissaperAnimation.duration = NSTimeInterval(leftAnimationDuration)
dissaperAnimation.fromValue = oneProgessLayer.strokeStart
dissaperAnimation.toValue = 1.0 - oneProgessLayer.strokeEnd
dissaperAnimation.fillMode = kCAFillModeForwards
dissaperAnimation.removedOnCompletion = false
oneProgessLayer.addAnimation(dissaperAnimation, forKey: "strokeStart")
}
}
//背景灰色Layer一直在清除,清除完畢圓環即繪製完成
var bgDuration = duration * (1.0 - backgroundLayer.strokeStart)
var bgAnimation = CABasicAnimation(keyPath: "strokeStart")
bgAnimation.duration = NSTimeInterval(bgDuration)
bgAnimation.fromValue = backgroundLayer.strokeStart
bgAnimation.removedOnCompletion = false
bgAnimation.toValue = 1.0
bgAnimation.delegate = self
backgroundLayer.addAnimation(bgAnimation, forKey: "otherStrokeEnd")
}
7.每當圓環未完成結束觸摸的時候,都要保存當前每個layer的strokeStart和strokeEnd,不要忘記背景圓環
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for oneProgessLayer in layerArray {
oneProgessLayer.strokeStart = oneProgessLayer.presentationLayer().strokeStart
oneProgessLayer.strokeEnd = oneProgessLayer.presentationLayer().strokeEnd
oneProgessLayer.removeAllAnimations()
}
backgroundLayer.strokeStart = backgroundLayer.presentationLayer().strokeStart
backgroundLayer.removeAllAnimations()
}
8.完成的標誌就是背景圓環整個被清除掉,所以只有背景圓環才設置了delegate
override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
if flag == true{
circleComplete = true
for oneProgessLayer in layerArray {
oneProgessLayer.strokeStart = oneProgessLayer.presentationLayer().strokeStart
oneProgessLayer.strokeEnd = oneProgessLayer.presentationLayer().strokeEnd
oneProgessLayer.removeAllAnimations()
}
backgroundLayer.strokeEnd = backgroundLayer.presentationLayer().strokeEnd
backgroundLayer.strokeStart = backgroundLayer.presentationLayer().strokeEnd
backgroundLayer.removeAllAnimations()
}
}
let progessView = CustomProgessView(frame: CGRectMake(CGRectGetMidX(view.bounds) - 150, 100, 300, 300))
view.addSubview(progessView)
結束。