水波纹效果

QQ20170816-103932.gif

整体思路

1.创建路径(path),使用正弦函数计算一点坐标(x,y),将所有的点连接成线,绘画出路径。
2.创建CAShapeLayer图层,根据路径绘画出波形效果。
3.使用CADispalyLink定时器,改变路径,做出动画效果。

代码说明

效果的实现主要是路径的绘制。理解正弦和余弦函数最为关键。可以参考iOS水波纹动画详解
代码来源iOS 水波表现进度的动画效果实现以及demo

注意问题

需要注意的问题ios坐标系x左边是正方向,y下边是正方向。绘画出的路径需要填充的区域如图所示:

屏幕快照 2017-08-16 上午11.29.58.png

单个波形,有渐变效果

//
//  YSWaterWaveView.m
//  Wave
//
//  Created by moshuqi on 16/1/7.
//  Copyright © 2016年 msq. All rights reserved.
//

#import "YSWaterWaveView.h"

@interface YSWaterWaveView ()

@property (nonatomic, strong) CADisplayLink *displayLink;

@property (nonatomic, strong) CAShapeLayer *waveLayer;  // 绘制波形
@property (nonatomic, strong) CAGradientLayer *gradientLayer;   // 绘制渐变

@property (nonatomic, strong) NSArray *colors;  // 渐变的颜色数组
@property (nonatomic, assign) CGFloat percent;  // 波浪上升的比例

// 绘制波形的变量定义,使用波形曲线y=Asin(ωx+φ)+k进行绘制
@property (nonatomic, assign) CGFloat waveAmplitude;  // 波纹振幅,A
@property (nonatomic, assign) CGFloat waveCycle;      // 波纹周期,T = 2π/ω

@property (nonatomic, assign) CGFloat offsetX;        // 波浪x位移,φ
@property (nonatomic, assign) CGFloat waveSpeed;      // 波纹速度,用来累加到相位φ上,达到波纹水平移动的效果

@property (nonatomic, assign) CGFloat currentWavePointY;    // 当前波浪高度,k
@property (nonatomic, assign) CGFloat waveGrowth;     // 波纹上升速度,累加到k上,达到波浪高度上升的效果

@property (nonatomic, assign) BOOL bWaveFinished;   // 上升完成

// 用来计算波峰一定范围内的波动值
@property (nonatomic, assign) BOOL increase;
@property (nonatomic, assign) CGFloat variable;

@end

@implementation YSWaterWaveView

static const CGFloat kExtraHeight = 20;     // 保证水波波峰不被裁剪,增加部分额外的高度

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self defaultConfig];
        
        self.backgroundColor = [UIColor colorWithRed:4 / 255.0 green:181 / 255.0 blue:108 / 255.0 alpha:1];
    }
    
    return self;
}

- (void)setGrowthSpeed:(CGFloat)growthSpeed
{
    self.waveGrowth = growthSpeed;
}

- (void)setGradientColors:(NSArray *)colors
{
    // 必须保证传进来的参数为UIColor*的数组
    NSMutableArray *array = [NSMutableArray array];
    for (UIColor *color in colors)
    {
        [array addObject:(__bridge id)color.CGColor];
    }
    
    self.colors = array;
}

- (void)setColorsWithArray:(NSArray *)colors
{
    self.colors = colors;
}

- (void)defaultConfig
{
    // 默认设置一些属性
    self.waveCycle = 1.66 * M_PI / CGRectGetWidth(self.frame);     // 影响波长
    self.currentWavePointY = CGRectGetHeight(self.frame) * self.percent;       // 波纹从下往上升起
    
    self.waveGrowth = 1.0;
    self.waveSpeed = 0.4 / M_PI;
    
    self.offsetX = 0;
}

- (void)resetProperty
{
    // 重置属性
    self.currentWavePointY = CGRectGetHeight(self.frame) * self.percent;
    self.offsetX = 0;
    
    self.variable = 1.6;
    self.increase = NO;
}

- (void)resetLayer
{
    // 动画开始之前重置layer
    if (self.waveLayer)
    {
        [self.waveLayer removeFromSuperlayer];
        self.waveLayer = nil;
    }
    self.waveLayer = [CAShapeLayer layer];
    
    // 设置渐变
    if (self.gradientLayer)
    {
        [self.gradientLayer removeFromSuperlayer];
        self.gradientLayer = nil;
    }
    self.gradientLayer = [CAGradientLayer layer];
    
    
    self.gradientLayer.frame = [self gradientLayerFrame];
    [self setupGradientColor];
    
    [self.gradientLayer setMask:self.waveLayer];
    [self.layer addSublayer:self.gradientLayer];
    
}

- (void)setupGradientColor
{
    // gradientLayer设置渐变色
    if ([self.colors count] < 1)
    {
        self.colors = [self defaultColors];
    }
    
    self.gradientLayer.colors = self.colors;
    
    //设定颜色分割点
    NSInteger count = [self.colors count];
    CGFloat d = 1.0 / count;
    
    NSMutableArray *locations = [NSMutableArray array];
    for (NSInteger i = 0; i < count; i++)
    {
        NSNumber *num = @(d + d * i);
        [locations addObject:num];
    }
    NSNumber *lastNum = @(1.0f);
    [locations addObject:lastNum];
    
    self.gradientLayer.locations = locations;
    
    // 设置渐变方向,从上往下
    self.gradientLayer.startPoint = CGPointMake(0, 0);
    self.gradientLayer.endPoint = CGPointMake(0, 1);
}

- (CGRect)gradientLayerFrame
{
    // gradientLayer在上升完成之后的frame值,如果gradientLayer在上升过程中不断变化frame值会导致一开始绘制卡顿,所以只进行一次赋值
    
    CGFloat gradientLayerHeight = CGRectGetHeight(self.frame) * self.percent + kExtraHeight;
    
    if (gradientLayerHeight > CGRectGetHeight(self.frame))
    {
        gradientLayerHeight = CGRectGetHeight(self.frame);
    }
    
    CGRect frame = CGRectMake(0, CGRectGetHeight(self.frame) - gradientLayerHeight, CGRectGetWidth(self.frame), gradientLayerHeight);
    
    return frame;
}

- (NSArray *)defaultColors
{
    // 默认的渐变色
    UIColor *color0 = [UIColor colorWithRed:164 / 255.0 green:216 / 255.0 blue:222 / 255.0 alpha:1];
    UIColor *color1 = [UIColor colorWithRed:105 / 255.0 green:192 / 255.0 blue:154 / 255.0 alpha:1];
    
    NSArray *colors = @[(__bridge id)color0.CGColor, (__bridge id)color1.CGColor];
    return colors;
}

- (void)startWaveToPercent:(CGFloat)percent
{
    self.percent = percent;
    
    [self resetProperty];
    [self resetLayer];
    
    if (self.displayLink)
    {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    
    self.bWaveFinished = NO;
    
    // 启动同步渲染绘制波纹
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(setCurrentWave:)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)stopWave
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)setCurrentWave:(CADisplayLink *)displayLink
{
    if ([self waveFinished])
    {
        self.bWaveFinished = YES;
        [self amplitudeReduce];
        // 减小到0之后动画停止。
        NSLog(@"完成amplitude = %lf",self.waveAmplitude);
        if (self.waveAmplitude <= 0)
        {
            [self stopWave];
            return;
        }
    }
    else
    {
        // 波浪高度未到指定高度 继续上涨
        [self amplitudeChanged];
        self.currentWavePointY -= self.waveGrowth;
    }
    
    self.offsetX += self.waveSpeed;
    [self setCurrentWaveLayerPath];
}

- (BOOL)waveFinished
{
    // 波浪上升动画是否完成
    CGFloat d = CGRectGetHeight(self.frame) - CGRectGetHeight(self.gradientLayer.frame);
    CGFloat extraH = MIN(d, kExtraHeight);
    BOOL bFinished = self.currentWavePointY <= extraH;
    
    return bFinished;
}

- (void)setCurrentWaveLayerPath
{
    // 通过正弦曲线来绘制波浪形状
    CGMutablePathRef path = CGPathCreateMutable();
    CGFloat y = self.currentWavePointY;
    
    CGPathMoveToPoint(path, nil, 0, y);
    CGFloat width = CGRectGetWidth(self.frame);
    NSLog(@"k == %lf",self.currentWavePointY);
    for (float x = 0.0f; x <= width; x++)
    {
        // 正弦波浪公式
        y = self.waveAmplitude * sin(self.waveCycle * x + self.offsetX) + self.currentWavePointY;
        //坐标系决定的 x和y的正方向向下。
        CGPathAddLineToPoint(path, nil, x, y);
    }
    
    //path 路径封好
    CGPathAddLineToPoint(path, nil, width, CGRectGetHeight(self.frame));
    CGPathAddLineToPoint(path, nil, 0, CGRectGetHeight(self.frame));
    CGPathCloseSubpath(path);
    
    self.waveLayer.path = path;
    CGPathRelease(path);
}

- (void)amplitudeChanged
{
    // 波峰在一定范围之内进行轻微波动
    
    // 波峰该继续增大或减小
    if (self.increase)
    {
        self.variable += 0.01;
    }
    else
    {
        self.variable -= 0.01;
    }
    
    // 变化的范围
    if (self.variable <= 1)
    {
        self.increase = YES;
    }
    
    if (self.variable >= 1.6)
    {
        self.increase = NO;
    }
    NSLog(@"variable = %lf",self.variable);
    // 根据variable值来决定波峰
    self.waveAmplitude = self.variable * 5;
    NSLog(@"amplitude = %lf",self.waveAmplitude);

}

- (void)amplitudeReduce
{
    // 波浪上升完成后,波峰开始逐渐降低
    self.waveAmplitude -= 0.066;
}

@end

单个波形,无渐变效果

//
//  YSWaterWaveView.m
//  Wave
//
//  Created by moshuqi on 16/1/7.
//  Copyright © 2016年 msq. All rights reserved.
//

#import "YSWaterWaveView.h"

@interface YSWaterWaveView ()

@property (nonatomic, strong) CADisplayLink *displayLink;

@property (nonatomic, strong) CAShapeLayer *waveLayer;  // 绘制波形
@property (nonatomic, strong) CAShapeLayer *waveLayerCos;  // 绘制余弦波形
@property (nonatomic, strong) CAGradientLayer *gradientLayer;   // 绘制渐变

@property (nonatomic, strong) NSArray *colors;  // 渐变的颜色数组
@property (nonatomic, assign) CGFloat percent;  // 波浪上升的比例

// 绘制波形的变量定义,使用波形曲线y=Asin(ωx+φ)+k进行绘制
@property (nonatomic, assign) CGFloat waveAmplitude;  // 波纹振幅,A
@property (nonatomic, assign) CGFloat waveCycle;      // 波纹周期,T = 2π/ω

@property (nonatomic, assign) CGFloat offsetX;        // 波浪x位移,φ
@property (nonatomic, assign) CGFloat waveSpeed;      // 波纹速度,用来累加到相位φ上,达到波纹水平移动的效果

@property (nonatomic, assign) CGFloat currentWavePointY;    // 当前波浪高度,k
@property (nonatomic, assign) CGFloat waveGrowth;     // 波纹上升速度,累加到k上,达到波浪高度上升的效果

@property (nonatomic, assign) BOOL bWaveFinished;   // 上升完成

// 用来计算波峰一定范围内的波动值
@property (nonatomic, assign) BOOL increase;
@property (nonatomic, assign) CGFloat variable;

@end

@implementation YSWaterWaveView

static const CGFloat kExtraHeight = 20;     // 保证水波波峰不被裁剪,增加部分额外的高度

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self defaultConfig];
        
        self.backgroundColor = [UIColor colorWithRed:4 / 255.0 green:181 / 255.0 blue:108 / 255.0 alpha:1];
    }
    
    return self;
}

- (void)setGrowthSpeed:(CGFloat)growthSpeed
{
    self.waveGrowth = growthSpeed;
}

- (void)setGradientColors:(NSArray *)colors
{
    // 必须保证传进来的参数为UIColor*的数组
    NSMutableArray *array = [NSMutableArray array];
    for (UIColor *color in colors)
    {
        [array addObject:(__bridge id)color.CGColor];
    }
    
    self.colors = array;
}

- (void)setColorsWithArray:(NSArray *)colors
{
    self.colors = colors;
}

- (void)defaultConfig
{
    // 默认设置一些属性
    self.waveCycle = 1.66 * M_PI / CGRectGetWidth(self.frame);     // 影响波长
    self.currentWavePointY = CGRectGetHeight(self.frame) * self.percent;       // 波纹从下往上升起
    
    self.waveGrowth = 1.0;
    self.waveSpeed = 0.4 / M_PI;
    
    self.offsetX = 0;
}

- (void)resetProperty
{
    // 重置属性
    self.currentWavePointY = CGRectGetHeight(self.frame);
    self.offsetX = 0;
    
    self.variable = 1.6;
    self.increase = NO;
}

- (void)resetLayer
{
    // 动画开始之前重置layer
    if (self.waveLayer)
    {
        [self.waveLayer removeFromSuperlayer];
        self.waveLayer = nil;
    }
    self.waveLayer = [CAShapeLayer layer];
    self.waveLayer.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.width);
    self.waveLayer.backgroundColor = [UIColor orangeColor].CGColor;
    [self.layer addSublayer:self.waveLayer];
    
}

- (void)startWaveToPercent:(CGFloat)percent
{
    self.percent = percent;
    
    [self resetProperty];
    [self resetLayer];
    
    if (self.displayLink)
    {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    
    self.bWaveFinished = NO;
    
    // 启动同步渲染绘制波纹
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(setCurrentWave:)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)stopWave
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)setCurrentWave:(CADisplayLink *)displayLink
{
    if ([self waveFinished])
    {
        self.bWaveFinished = YES;
        [self amplitudeReduce];
        // 减小到0之后动画停止。
        NSLog(@"完成amplitude = %lf",self.waveAmplitude);
        if (self.waveAmplitude <= 0)
        {
            [self stopWave];
            return;
        }
    }
    else
    {
        // 波浪高度未到指定高度 继续上涨
        [self amplitudeChanged];
        self.currentWavePointY -= self.waveGrowth;
    }
    
    self.offsetX += self.waveSpeed;
    [self setCurrentWaveLayerPath];
}

- (BOOL)waveFinished
{
    // 波浪上升动画是否完成
    CGFloat d = CGRectGetHeight(self.frame) - CGRectGetHeight(self.waveLayer.frame)*self.percent;
    BOOL bFinished = self.currentWavePointY <= d;
    
    return bFinished;
}

- (void)setCurrentWaveLayerPath
{
    // 通过正弦曲线来绘制波浪形状
    CGMutablePathRef path = CGPathCreateMutable();
    CGFloat y = self.currentWavePointY;
    
    CGPathMoveToPoint(path, nil, 0, y);
    CGFloat width = CGRectGetWidth(self.frame);
    NSLog(@"k == %lf",self.currentWavePointY);
    for (float x = 0.0f; x <= width; x++)
    {
        // 正弦波浪公式
        y = self.waveAmplitude * sin(self.waveCycle * x + self.offsetX) + self.currentWavePointY;
        //坐标系决定的 x和y的正方向向下。
        CGPathAddLineToPoint(path, nil, x, y);
    }
    
    //path 路径封好
    CGPathAddLineToPoint(path, nil, width, CGRectGetHeight(self.frame));
    CGPathAddLineToPoint(path, nil, 0, CGRectGetHeight(self.frame));
    CGPathCloseSubpath(path);
    
    self.waveLayer.path = path;
    self.waveLayer.fillColor = [UIColor cyanColor].CGColor;
    CGPathRelease(path);
}

- (void)amplitudeChanged
{
    // 波峰在一定范围之内进行轻微波动
    
    // 波峰该继续增大或减小
    if (self.increase)
    {
        self.variable += 0.01;
    }
    else
    {
        self.variable -= 0.01;
    }
    
    // 变化的范围
    if (self.variable <= 1)
    {
        self.increase = YES;
    }
    
    if (self.variable >= 1.6)
    {
        self.increase = NO;
    }
    NSLog(@"variable = %lf",self.variable);
    // 根据variable值来决定波峰
    self.waveAmplitude = self.variable * 5;
    NSLog(@"amplitude = %lf",self.waveAmplitude);

}

- (void)amplitudeReduce
{
    // 波浪上升完成后,波峰开始逐渐降低
    self.waveAmplitude -= 0.066;
}

@end

双波形,无渐变效果

//
//  YSWaterWaveView.m
//  Wave
//
//  Created by moshuqi on 16/1/7.
//  Copyright © 2016年 msq. All rights reserved.
//

#import "YSWaterWaveView.h"

@interface YSWaterWaveView ()

@property (nonatomic, strong) CADisplayLink *displayLink;

@property (nonatomic, strong) CAShapeLayer *waveLayer;  // 绘制波形
@property (nonatomic, strong) CAShapeLayer *waveLayerCos;  // 绘制余弦波形
@property (nonatomic, strong) CAGradientLayer *gradientLayer;   // 绘制渐变

@property (nonatomic, strong) NSArray *colors;  // 渐变的颜色数组
@property (nonatomic, assign) CGFloat percent;  // 波浪上升的比例

// 绘制波形的变量定义,使用波形曲线y=Asin(ωx+φ)+k进行绘制
@property (nonatomic, assign) CGFloat waveAmplitude;  // 波纹振幅,A
@property (nonatomic, assign) CGFloat waveCycle;      // 波纹周期,T = 2π/ω

@property (nonatomic, assign) CGFloat offsetX;        // 波浪x位移,φ
@property (nonatomic, assign) CGFloat waveSpeed;      // 波纹速度,用来累加到相位φ上,达到波纹水平移动的效果

@property (nonatomic, assign) CGFloat currentWavePointY;    // 当前波浪高度,k
@property (nonatomic, assign) CGFloat waveGrowth;     // 波纹上升速度,累加到k上,达到波浪高度上升的效果

@property (nonatomic, assign) BOOL bWaveFinished;   // 上升完成

// 用来计算波峰一定范围内的波动值
@property (nonatomic, assign) BOOL increase;
@property (nonatomic, assign) CGFloat variable;

@end

@implementation YSWaterWaveView

static const CGFloat kExtraHeight = 20;     // 保证水波波峰不被裁剪,增加部分额外的高度

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self defaultConfig];
        
        self.backgroundColor = [UIColor colorWithRed:4 / 255.0 green:181 / 255.0 blue:108 / 255.0 alpha:1];
    }
    
    return self;
}

- (void)setGrowthSpeed:(CGFloat)growthSpeed
{
    self.waveGrowth = growthSpeed;
}

- (void)setGradientColors:(NSArray *)colors
{
    // 必须保证传进来的参数为UIColor*的数组
    NSMutableArray *array = [NSMutableArray array];
    for (UIColor *color in colors)
    {
        [array addObject:(__bridge id)color.CGColor];
    }
    
    self.colors = array;
}

- (void)setColorsWithArray:(NSArray *)colors
{
    self.colors = colors;
}

- (void)defaultConfig
{
    // 默认设置一些属性
    self.waveCycle = 1.66 * M_PI / CGRectGetWidth(self.frame);     // 影响波长
    self.currentWavePointY = CGRectGetHeight(self.frame) * self.percent;       // 波纹从下往上升起
    
    self.waveGrowth = 1.0;
    self.waveSpeed = 0.4 / M_PI;
    
    self.offsetX = 0;
}

- (void)resetProperty
{
    // 重置属性
    self.currentWavePointY = CGRectGetHeight(self.frame);
    self.offsetX = 0;
    
    self.variable = 1.6;
    self.increase = NO;
}

- (void)resetLayer
{
    // 动画开始之前重置layer
    if (self.waveLayer)
    {
        [self.waveLayer removeFromSuperlayer];
        self.waveLayer = nil;
    }
    self.waveLayer = [CAShapeLayer layer];
    self.waveLayer.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.width);
    self.waveLayer.backgroundColor = [UIColor orangeColor].CGColor;
    self.waveLayer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.3f].CGColor;
    [self.layer addSublayer:self.waveLayer];
    
    
    if (self.waveLayerCos)
    {
        [self.waveLayerCos removeFromSuperlayer];
        self.waveLayerCos = nil;
    }
    self.waveLayerCos = [CAShapeLayer layer];
    self.waveLayerCos.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.width);
    self.waveLayerCos.backgroundColor = [UIColor clearColor].CGColor;
    self.waveLayerCos.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.3f].CGColor;
//    self.waveLayerCos.opacity = 0.5;
    [self.layer addSublayer:self.waveLayerCos];

}

- (void)startWaveToPercent:(CGFloat)percent
{
    self.percent = percent;
    
    [self resetProperty];
    [self resetLayer];
    
    if (self.displayLink)
    {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    
    self.bWaveFinished = NO;
    
    // 启动同步渲染绘制波纹
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(setCurrentWave:)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)stopWave
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)setCurrentWave:(CADisplayLink *)displayLink
{
    if ([self waveFinished])
    {
        self.bWaveFinished = YES;
        [self amplitudeReduce];
        // 减小到0之后动画停止。
        NSLog(@"完成amplitude = %lf",self.waveAmplitude);
        if (self.waveAmplitude <= 0)
        {
            [self stopWave];
            return;
        }
    }
    else
    {
        // 波浪高度未到指定高度 继续上涨
        [self amplitudeChanged];
        self.currentWavePointY -= self.waveGrowth;
    }
    
    self.offsetX += self.waveSpeed;
    [self setCurrentWaveLayerPath];
}

- (BOOL)waveFinished
{
    // 波浪上升动画是否完成
    CGFloat d = CGRectGetHeight(self.frame) - CGRectGetHeight(self.waveLayer.frame)*self.percent;
    BOOL bFinished = self.currentWavePointY <= d;
    
    return bFinished;
}

- (void)setCurrentWaveLayerPath
{
    // 通过正弦曲线来绘制波浪形状
    CGMutablePathRef path = CGPathCreateMutable();
    CGFloat y = self.currentWavePointY;
    
    CGPathMoveToPoint(path, nil, 0, y);
    CGFloat width = CGRectGetWidth(self.frame);
    NSLog(@"k == %lf",self.currentWavePointY);
    for (float x = 0.0f; x <= width; x++)
    {
        // 正弦波浪公式
        y = self.waveAmplitude * sin(self.waveCycle * x + self.offsetX) + self.currentWavePointY;
        //坐标系决定的 x和y的正方向向下。
        CGPathAddLineToPoint(path, nil, x, y);
    }
    
    //path 路径封好
    CGPathAddLineToPoint(path, nil, width, CGRectGetHeight(self.frame));
    CGPathAddLineToPoint(path, nil, 0, CGRectGetHeight(self.frame));
    CGPathCloseSubpath(path);
    
    self.waveLayer.path = path;
    CGPathRelease(path);
    
    
    CGMutablePathRef pathCos = CGPathCreateMutable();
    
    CGPathMoveToPoint(pathCos, nil, 0, y);
    for (float x = 0.0f; x <= width; x++)
    {
        // 正弦波浪公式
        y = self.waveAmplitude * cos(self.waveCycle * x + self.offsetX) + self.currentWavePointY;
        //坐标系决定的 x和y的正方向向下。
        CGPathAddLineToPoint(pathCos, nil, x, y);
    }
    
    //path 路径封好
    CGPathAddLineToPoint(pathCos, nil, width, CGRectGetHeight(self.frame));
    CGPathAddLineToPoint(pathCos, nil, 0, CGRectGetHeight(self.frame));
    CGPathCloseSubpath(pathCos);
    
    self.waveLayerCos.path = pathCos;
    
    CGPathRelease(pathCos);

}

- (void)amplitudeChanged
{
    // 波峰在一定范围之内进行轻微波动
    
    // 波峰该继续增大或减小
    if (self.increase)
    {
        self.variable += 0.01;
    }
    else
    {
        self.variable -= 0.01;
    }
    
    // 变化的范围
    if (self.variable <= 1)
    {
        self.increase = YES;
    }
    
    if (self.variable >= 1.6)
    {
        self.increase = NO;
    }
    NSLog(@"variable = %lf",self.variable);
    // 根据variable值来决定波峰
    self.waveAmplitude = self.variable * 5;
    NSLog(@"amplitude = %lf",self.waveAmplitude);

}

- (void)amplitudeReduce
{
    // 波浪上升完成后,波峰开始逐渐降低
    self.waveAmplitude -= 0.066;
}

@end

头文件

//
//  YSWaterWaveView.h
//  Wave
//
//  Created by moshuqi on 16/1/7.
//  Copyright © 2016年 msq. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface YSWaterWaveView : UIView

- (void)startWaveToPercent:(CGFloat)percent;

- (void)setGrowthSpeed:(CGFloat)growthSpeed;    // 设置上升速度
- (void)setGradientColors:(NSArray *)colors;    // 设置渐变色

@end

调用方法

   CGFloat d = 160;
    CGRect rect = CGRectMake(0, 0, d, d);
    YSWaterWaveView *waterWaveView = [[YSWaterWaveView alloc] initWithFrame:rect];
    
    waterWaveView.center = self.view.center;
    waterWaveView.layer.cornerRadius = d / 2;
    waterWaveView.clipsToBounds = YES;
    
    [self.view addSubview:waterWaveView];
    
    [waterWaveView startWaveToPercent:0.8];

正弦型函数解析式:y=Asin(ωx+φ)+k在本文中的使用
*A:振幅,振幅决定了波纹起伏的大小,是一个一直变化的值,而且当波纹达到想要的高度后振幅会逐渐减小至零,当振幅小于零时,波纹已经成一条直线,在这里需要将定时器关闭。代码中使用两个变量(self.increase和self.variable)改变振幅的大小。
*w:角速度,和波长有关系,其他情况不变的情况下,角速度越大,单个波长的周
期(T = 2 *M_PI/W)越短,波长越短。代码中角速度(self.waveCycle)是一个定值。
*x:点在x方向的位置。
*φ:初相位,代码中使用self.offsetX来表示,通过self.waveSpeed改变self.offsetX大小。
*k:正弦函数在坐标系Y上的偏移量,想要达到的高度由它来控制,因为Y坐标正方向向下,所以代码中控制它的变量(self.currentWavePointY)是递减的,递减变量用self.waveGrowth控制。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容