在工程中碰到了需要实现波浪动画。只知道是使用正弦函数和余弦函数,CADisplayLink来实现。
正弦,余弦函数就不多说了 y = Asin(ωx+φ) + k,不同的参数控制正弦曲线的显示效果。
A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
(ωx+φ)——相位,反映变量y所处的状态。
φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
k——偏距,反映在坐标系上则为图像的上移或下移。
ω——角速度, 控制正弦周期(单位角度内震动的次数)。
CADisplayLink 这个对象和 NSTimer 类似,是一个定时触发指定方法对象,同样也需要加入一个 NSRunLoop 内才能持续执行。
CADisplayLink 执行的周期和 NSTimer 又不相同,NSTimer 可以自定义周期,而 CADisplayLink 是根据屏幕刷新周期为周期(1/60秒)
如下图:
一、绘制静态曲线
波浪效果其实说白了就是两条移动的正余弦曲线,而绘制曲线则需要正余弦函数。
首先来看下不会动的波浪。
曲线可以看做一段段很短的直线连接起来绘制的。
绘制直线则可以使用 Core Graphics 或 UIBezierPath 在 CAShapeLayer 来绘制。
- (CAShapeLayer *)firstWavelayer {
if (!_firstWavelayer) {
_firstWavelayer = [CAShapeLayer layer];
_firstWavelayer.fillColor = [UIColor yellowColor].CGColor; // 填充色
_firstWavelayer.strokeColor = [UIColor blueColor].CGColor; // 线的颜色
}
return _firstWavelayer;
} // 懒加载一个 CAShapeLayer
绘制一条正弦曲线
- (void)drawFirstWave {
_waveMoveFirst = _waveMoveFirst + 0.2;
[self.layer addSublayer:self.firstWavelayer];
CGMutablePathRef ref = CGPathCreateMutable();
CGPathMoveToPoint(ref, nil, 0, self.frame.size.height);
// 根据 y = Asin(ωx+φ) + k 的 x 变化来延展曲线,通过 φ 来移动曲线
for (NSInteger i = 0; i <= self.frame.size.width ; i++) {
double y = 10 * sin(0.1 * i + _waveMoveFirst) + 10;
CGPathAddLineToPoint(ref, nil, i, y);
}
//填充底部颜色
CGPathAddLineToPoint(ref, nil, self.bounds.size.width, self.bounds.size.height);
CGPathAddLineToPoint(ref, nil, 0, self.bounds.size.height);
CGPathCloseSubpath(ref);
self.firstWavelayer.path = ref;
CGPathRelease(ref);
}
通过以上代码则绘制一条静止的曲线。
第二条曲线和第一条绘制代码相同。
二、曲线动起来
要想曲线动起来根据 y = Asin(ωx+φ) + k,通过 φ 值的不断变化来实现移动。
创建一个:
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(moveWave)];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[_displayLink addToRunLoop:runloop forMode:NSRunLoopCommonModes];
- (void)moveWave {
[self drawFirstWave];
}
通过类型定时器 CADisplayLink 对象来 1/60 s 来执行一次 drawFirstWave 方法来实现 _waveMoveFirst 的值不断变化,从而达到曲线运动的效果。