效果图:
原理:
正弦曲线公式可表示为y=Asin(ωx+φ)+k:
A,振幅,最高和最低的距离
W,角速度,用于控制周期大小,单位x中的起伏个数
K,偏距,曲线整体上下偏移量
φ,初相,左右移动的值
添加不同的曲线达到波浪效果
核心代码:
//控制数据
//设置进度 0~1
@property (assign,nonatomic) CGFloat progress;
//曲线移动速度
@property (nonatomic, assign) CGFloat waveMoveSpeed;
//曲线角速度
@property (nonatomic, assign) CGFloat wavePalstance;
//颜色
@property (nonatomic, strong) NSArray *colorArry;
{
//前面的波浪
CAShapeLayer *_waveLayer1;
CAShapeLayer *_waveLayer2;
CAShapeLayer *_waveLayer3;
CADisplayLink *_disPlayLink;
//曲线的振幅
CGFloat _waveAmplitude;
//曲线初相
CGFloat _waveX;
//曲线偏距
CGFloat _waveY;
}
-(instancetype)initWithFrame:(CGRect)frame AndColorArray:(NSArray *)colorArry {
if (self = [super initWithFrame:frame]) {
_colorArry = colorArry;
_bgColor = colorArry[0];
_waveColor1 = colorArry[1];
_waveColor2 = colorArry[2];
_waveColor3 = colorArry[3];
_progress = 0.9;
}
return self;
}
//初始化波浪
//底层
_waveLayer1 = [CAShapeLayer layer];
_waveLayer1.fillColor = _waveColor1.CGColor;
_waveLayer1.strokeColor = _waveColor1.CGColor;
[self.layer addSublayer:_waveLayer1];
//中层
_waveLayer2 = [CAShapeLayer layer];
_waveLayer2.fillColor = _waveColor2.CGColor;
_waveLayer2.strokeColor = _waveColor2.CGColor;
[self.layer addSublayer:_waveLayer2];
//上层
_waveLayer3 = [CAShapeLayer layer];
_waveLayer3.fillColor = _waveColor3.CGColor;
_waveLayer3.strokeColor = _waveColor3.CGColor;
[self.layer addSublayer:_waveLayer3];
//初始化数据
//振幅
_waveAmplitude = self.bounds.size.height *(1 - _progress -0.02);//这里的数据处理是为了在顶部流出一定的空间,波浪效果会好一点
//角速度
_wavePalstance = M_PI/self.bounds.size.width;
//偏距
// _waveY = self.bounds.size.height * _progress;
_waveY = self.bounds.size.height *(1 - _progress);
//初相
_waveX = 0;
//x轴移动速度
_waveMoveSpeed = _wavePalstance * 4;//这里的速度可以自由调节,达到你想要的效果
//以屏幕刷新速度为周期刷新曲线的位置
_disPlayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateWave:)];
[_disPlayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
//波浪的变化
-(void)updateWave:(CADisplayLink *)link
{
_waveX += _waveMoveSpeed;
[self updateWaveY];
[self updateWave1];
[self updateWave2];
[self updateWave3];
}
//更新偏距的大小 直到达到目标偏距 让wave有一个匀速增长的效果
-(void)updateWaveY
{
CGFloat targetY = self.bounds.size.height - _progress * self.bounds.size.height;
//动画效果:波浪从无到有,或者可以做成上下浮动的效果,这个波浪的高度由_progress控制
// if (_waveY < targetY) {
// _waveY += 2;
// }
// if (_waveY > targetY ) {
// _waveY -= 2;
// }
//无动画效果
if (_waveY != targetY) {
_waveY = targetY;
}
}
//绘制波浪
-(void)updateWave1
{
//波浪宽度
CGFloat waterWaveWidth = self.bounds.size.width;
//初始化运动路径
CGMutablePathRef path = CGPathCreateMutable();
//设置起始位置
CGPathMoveToPoint(path, nil, 0, _waveY);
//初始化波浪其实Y为偏距
CGFloat y = _waveY;
//正弦曲线公式为: y=Asin(ωx+φ)+k;
for (float x = 0.0f; x <= waterWaveWidth ; x++) {
y = _waveAmplitude * cos(_wavePalstance * x + _waveX + M_PI/2) + _waveY;
CGPathAddLineToPoint(path, nil, x, y);
}
//填充底部颜色
CGPathAddLineToPoint(path, nil, waterWaveWidth, self.bounds.size.height);
CGPathAddLineToPoint(path, nil, 0, self.bounds.size.height);
CGPathCloseSubpath(path);
_waveLayer1.path = path;
CGPathRelease(path);
}
//我在这里的波浪2函数,没有 M_PI/2
for (float x = 0.0f; x <= waterWaveWidth ; x++) {
y = _waveAmplitude * sin(_wavePalstance * x + _waveX) + _waveY;
CGPathAddLineToPoint(path, nil, x, y);
}
//我在这里的波浪3函数,用cos函数
for (float x = 0.0f; x <= waterWaveWidth ; x++) {
y = _waveAmplitude * cos(_wavePalstance * x + _waveX) + _waveY;
CGPathAddLineToPoint(path, nil, x, y);
}
//控件的外部控制参数
-(void)setProgress:(CGFloat)progress
{
_progress = progress;
}
//控件外部,控制波浪颜色
- (void)setColorArry:(NSArray *)colorArry {
_colorArry = colorArry;
_bgColor = colorArry[0];
_waveColor1 = colorArry[1];
_waveColor2 = colorArry[2];
_waveColor3 = colorArry[3];
//底层
_waveLayer1.fillColor = _waveColor1.CGColor;
_waveLayer1.strokeColor = _waveColor1.CGColor;
//中层
_waveLayer2.fillColor = _waveColor2.CGColor;
_waveLayer2.strokeColor = _waveColor2.CGColor;
//上层
_waveLayer3.fillColor = _waveColor3.CGColor;
_waveLayer3.strokeColor = _waveColor3.CGColor;
}
//停止动画效果
-(void)stop
{
if (_disPlayLink) {
[_disPlayLink invalidate];
_disPlayLink = nil;
}
}
//注销波浪
-(void)dealloc
{
[self stop];
if (_waveLayer1) {
[_waveLayer1 removeFromSuperlayer];
_waveLayer1 = nil;
}
if (_waveLayer2) {
[_waveLayer2 removeFromSuperlayer];
_waveLayer2 = nil;
}
if (_waveLayer3) {
[_waveLayer3 removeFromSuperlayer];
_waveLayer3 = nil;
}
}