使用UIBezierPath绘制波浪

我们经常会在一些应用里边见到波浪的动画,比如之前淘宝个人中心顶部的双波浪,今天我们就来看一下这个效果是怎么实现的。

原理

绘制波浪

实际上这个波浪就是使用正弦曲线公式 y=Asin(wx+u)+K绘制出来的,具体样式如图。

logo

各个参数代表的意义如下:

  • A:振幅,控制波浪的高度;
  • w:角速度 w = 2PI/T;
  • T:周期;
  • u:初相;
  • K:y轴方向上的偏移量。

动起来

如何能让波浪在画面上动起来呢,我们可以使用CADisplayLink或者NSTimer使画面中的线条一直在绘制。

这里推荐使用CADisplayLink 因为它可以保持较高的刷新率,刷新率为每秒60次。

在使用CADisplayLink时调用UIView中的drawRect方法不停地重绘页面。就可以实现动画的样式。

实现的效果就是这样:

logo

实现

首先我们先创建一个UIView并且注册一个CADisplayLink定时器,并把它加入到NSMainRunLoop中。

1
2
self.waveDisplayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(runWave)];
[self.waveDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

在调用的runWave中我们使用setNeedsDisplay方法调用UIView的drawRect方法,在这里我改变了K的值,也就是_waterLineY来让波浪一直向下移动,并且通过改变_waveCycle让波浪移动。

1
2
3
4
5
6
7
- (void)runWave
{
_waterLineY += 0.1;
_waveCycle += 0.1;
[self setNeedsDisplay];
}

然后在drawRect中绘制正弦曲线就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)drawRect:(CGRect)rect
{
UIBezierPath *wavePath = [UIBezierPath bezierPath];
[wavePath moveToPoint:CGPointMake(0, self.waterLineY)];
for(float x = 0 ; x <=WIDTH ; x++)
{
CGFloat y = _waveAmplitude * sin(x/180*M_PI + 4*_waveCycle/M_PI ) * 5 + _waterLineY;
[wavePath addLineToPoint:CGPointMake(x, y)];
}
[wavePath addLineToPoint:CGPointMake(WIDTH, HEIGHT)];
[wavePath addLineToPoint:CGPointMake(0, HEIGHT)];
[wavePath closePath];
self.shapeLayer.path = wavePath.CGPath;
}