UIBezierPath实现波浪动画

作者 john 日期 2016-11-08 阅读量
UIBezierPath实现波浪动画

Mark:

最近使用频繁的CAShaperLayer、CABasicAnimation、CAKeyframeAnimation,突然想实现一个以前APP中波浪线,效果如下:


这里写图片描述

开始的调查发现,核心在于使用正弦函数sinf生成点,但是没有想到使用CGMutablePathRef以点划线,然后通过不停的改变sinf中的参数以及结果,来实现动画的效果。


我使用了UIBezierPath,但是常规的UIBezierPath只有最多两个controlPoint,例如下面:

代码实现:

1
2
path.move(to: _point)
path.addCurve(to: _point1, controlPoint1: con1, controlPoint2: con2)

那么也就能画出一个周期:
这里写图片描述

看来不能用现成的方法,那么UIBezierPath能不能自己addLine加点呢?我当时贱贱的想,其实是可以的,话不多说,上代码


在新建的WaveView.m中


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
override func draw(_ rect: CGRect) {
// layer
backg = CAShapeLayer()
backg.lineWidth = 1
backg.strokeColor = UIColor.clear.cgColor
backg.fillColor = UIColor.clear.cgColor
backg.opacity = 0.5
// layer1
backg_ = CAShapeLayer()
backg_.lineWidth = 1
backg_.strokeColor = UIColor.clear.cgColor
backg_.fillColor = UIColor.clear.cgColor
backg_.opacity = 0.5
// 贝塞尔曲线
bezierPath = UIBezierPath()
// 添加layers
self.layer.addSublayer(backg)
self.layer.addSublayer(backg_)
// 定时,之所以用CADisplayLink做timer,下面会解释
let link = CADisplayLink(target: self, selector: #selector(animation))
link.add(to: RunLoop.main, forMode: .commonModes)
}


在每一帧执行一次的animation()中,给bezierPath划线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
func animation() {
// 第一个layer
bezierPath.removeAllPoints() // 清空上一次的所有点,也就是擦除上一次的波浪线
offset += 2
//var startY = 10.0*sinf(Float(M_PI*Double(offset)/375.0))
print(startY)
bezierPath.move(to: CGPoint(x: 0, y: 240)) // 设置起点
// 终点和control点不用设置,通过下面的正弦函数计算,依靠addLine手动设置
// 通过for生成一系列的point,当然,point.y的值是根据正弦sinf生成的
for i in 0...374 {
let a = 2.5*M_PI*Double(i)/375.0
let b = Double(offset)*M_PI/375.0
let y = 1.1*10.0*sinf(Float(a+b)) + 200
// 将点连线
bezierPath.addLine(to: CGPoint(x: CGFloat(i), y: CGFloat(y)))
}
// 闭环
bezierPath.addLine(to: CGPoint(x: 375, y: 240)) // 设置终点
backg.fillColor = UIColor.lightGray.cgColor
backg.opacity = 0.5
backg.path = bezierPath.cgPath
// 同理第二个layer
bezierPath.removeAllPoints()
offset += 2
bezierPath.move(to: CGPoint(x: 0, y: 240))
for i in 0...374 {
let a = 2.5*M_PI*Double(i)/375.0
let b = Double(3*offset)*M_PI/375.0
let y = 10.0*sinf(Float(a+b+M_PI/4)) + 200
bezierPath.addLine(to: CGPoint(x: CGFloat(i), y: CGFloat(y)))
}
bezierPath.addLine(to: CGPoint(x: 375, y: 240))
backg_.fillColor = UIColor.lightGray.cgColor
backg_.opacity = 0.5
backg_.path = bezierPath.cgPath
}


将WaveView加入父视图显示,效果图:


这里写图片描述

gif的原因,最后有点闪,实际流畅的很呢^_^

demo地址:

demo地址:https://github.com/jakajacky/DRBezierWave