前几天看了一篇关于动画的博客叫手摸手教你写 Slack 的 Loading 动画,看着挺炫,但是是安卓版的,寻思的着仿造着写一篇iOS版的,下面是我写这个动画的分解~
老规矩先上图和demo地址:

刚看到这个动画的时候,脑海里出现了两个方案,一种是通过drawRect画出来,然后配合CADisplayLink不停的绘制线的样式;第二种是通过CAShapeLayer配合CAAnimation来实现动画效果。再三考虑觉得使用后者,因为前者需要计算很多,比较复杂,而且经过测试前者相比于后者消耗更多的CPU,下面将我的思路写下来:
相关配置和初始化方法
在写这个动画之前,我们把先需要的属性写好,比如线条的粗细,动画的时间等等,下面是相关的配置和初识化方法:
//线的宽度
var lineWidth:CGFloat = 0
//线的长度
var lineLength:CGFloat = 0
//边距
var margin:CGFloat = 0
//动画时间
var duration:Double = 2
//动画的间隔时间
var interval:Double = 1
//四条线的颜色
var colors:[UIColor] = [UIColor.init(rgba: "#9DD4E9") , UIColor.init(rgba: "#F5BD58"), UIColor.init(rgba: "#FF317E") , UIColor.init(rgba: "#6FC9B5")]
//动画的状态
private(set) var status:AnimationStatus = .Normal
//四条线
private var lines:[CAShapeLayer] = []
enum AnimationStatus {
//普通状态
case Normal
//动画中
case Animating
//暂停
case pause
}
//MARK: Initial Methods
convenience init(fram: CGRect , colors: [UIColor]) {
self.init()
self.frame = frame
self.colors = colors
config()
}
override init(frame: CGRect) {
super.init(frame: frame)
config()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
config()
}
private func config() {
lineLength = max(frame.width, frame.height)
lineWidth = lineLength/6.0
margin = lineLength/4.5 + lineWidth/2
drawLineShapeLayer()
transform = CGAffineTransformRotate(CGAffineTransformIdentity, angle(-30))
}
通过CAShapeLayer绘制线条
看到这个线条我就想到了用CAShapeLayer来处理,因为CAShapeLayer完全可以实现这种效果,而且它的strokeEnd的属性可以用来实现线条的长度变化的动画,下面上绘制四根线条的代码:

//MARK: 绘制线
/**
绘制四条线
*/
private func drawLineShapeLayer() {
//开始点
let startPoint = [point(lineWidth/2, y: margin),
point(lineLength - margin, y: lineWidth/2),
point(lineLength - lineWidth/2, y: lineLength - margin),
point(margin, y: lineLength - lineWidth/2)]
//结束点
let endPoint = [point(lineLength - lineWidth/2, y: margin) ,
point(lineLength - margin, y: lineLength - lineWidth/2) ,
point(lineWidth/2, y: lineLength - margin) ,
point(margin, y: lineWidth/2)]
for i in 0...3 {
let line:CAShapeLayer = CAShapeLayer()
line.lineWidth = lineWidth
line.lineCap = kCALineCapRound
line.opacity = 0.8
line.strokeColor = colors[i].CGColor
line.path = getLinePath(startPoint[i], endPoint: endPoint[i]).CGPath
layer.addSublayer(line)
lines.append(line)
}
}
/**
获取线的路径
- parameter startPoint: 开始点
- parameter endPoint: 结束点
- returns: 线的路径
*/
private func getLinePath(startPoint: CGPoint, endPoint: CGPoint) -> UIBezierPath {
let path = UIBezierPath()
path.moveToPoint(startPoint)
path.addLineToPoint(endPoint)
return path
}
private func point(x:CGFloat , y:CGFloat) -> CGPoint {
return CGPointMake(x, y)
}
private func angle(angle: Double) -> CGFloat {
return CGFloat(angle * (M_PI/180))
}










