[iOS 水波浪动画作业]

参考贴连接

这里总结一下

1.核心公式

 正弦型函数解析式:y=Asin(ωx+φ)+h
     φ(初相位):决定波形与X轴位置关系或横向移动距离(左加右减)

     ω:决定周期(最小正周期T=2π/|ω|)

     A:决定峰值(即纵向拉伸压缩的倍数)

     h:表示波形在Y轴的位置关系或纵向移动距离(上加下减)

以上的公式一开始看不懂没关系, 参数看不懂也没关系
我们就拿我们知道的波峰/波宽/震幅等好理解的属性来设置

//我们需要两个shapelayer

    CAShapeLayer *waveLayer;  //水波浪1
    CAShapeLayer *waveLayerTwo; //水波浪2

//以及相关属性

    CGFloat speed;   //沿X轴波峰移动速度
    CGFloat offsetX; //沿X轴波峰移动偏移量
    CGFloat offsetY; //沿Y轴波起点位置(即公式中的h)
    CGFloat waveWidth; //水波浪总宽度
    CGFloat A;          //上下的振幅


1.speed : 这个决定了在UIkit坐标系下,水波浪线的point点的X坐标沿着X轴移动的速度
2.offsetX  这个决定了在UIkit坐标系下,水波浪线的point点在X轴上的位移(offsetX随着每秒60帧的CADisplayLink调用,会以speed为单位递增   offsetX += speed);
3.offsetY 这个决定了在UIkit坐标系下,水波浪线的point点在Y轴上的初始位置,说白了就是决定这个水波浪layer的整体(包括水波浪线和下面的矩形)高度
4 waveWidth 总宽度 ,这个没什么好说的
5.A 就是公式中的A 决定了振幅的大小,也就是波峰波谷上下震动的效果量

开始套用公式

    CGFloat y;
    CGFloat ω = 1.1*M_PI/waveWidth;
    CGFloat φ = offsetX*(M_PI/360.f);
    CGFloat h = offsetY;

    for (int x = 0; x <= waveWidth; x++) {
        y = A*sin*x + (- φ)) + h*1;  //坐标系差异 需要转换 UIkit中 Y轴向下
    }

其中 
'ω中的1.1 是在总宽度waveWidth下显示1.1个波曲线的意思'
'φ中的360 决定了初相位,两个相同参数的水波浪,设置初相位不同即可有波动差异,达到水波浪交错效果'

ps:由于CoreGraphics坐标系基于os系统,所以和UIKit所在的iOS系统下坐标系是上下垂直的,所以Y值翻转一下,当然你不翻转,那么水波浪的波动方向就是不从左到右,而是从右到左.

效果

这里写图片描述

完整代码

WaveAnimationView.h

//
//  WaveAnimationView.h
//  iOSWaveAnimationDemo
//
//  Created by tianNanYiHao on 2017/8/24.
//  Copyright © 2017年 tianNanYiHao. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface WaveAnimationView : UIView

@end

WaveAnimationView.m

//
//  WaveAnimationView.m
//  iOSWaveAnimationDemo
//
//  Created by tianNanYiHao on 2017/8/24.
//  Copyright © 2017年 tianNanYiHao. All rights reserved.
//

#import "WaveAnimationView.h"

@interface WaveAnimationView (){

    CAShapeLayer *waveLayer;  //水波浪1
    CAShapeLayer *waveLayerTwo; //水波浪2

    CADisplayLink *displayLink; //垂直刷新link

    CGFloat speed;   //沿X轴波峰移动速度
    CGFloat offsetX; //沿X轴波峰移动偏移量
    CGFloat offsetY; //沿Y轴波起点位置(即公式中的h)
    CGFloat waveWidth; //水波浪总宽度
    CGFloat A;          //上下的振幅



}

@end

@implementation WaveAnimationView


- (instancetype)initWithFrame:(CGRect)frame{
    if ([super initWithFrame:frame]) {

        speed = 2.f;
        offsetX = 0.f;
        offsetY = self.bounds.size.height *0.6f;
        waveWidth = self.bounds.size.width;
        A = 10.f;


        //创建水波纹layer
        waveLayer = [CAShapeLayer layer];
        waveLayer.fillColor = [UIColor colorWithRed:3/255.f green:144/255.f blue:144/255.f alpha:1.f].CGColor;
        [self.layer addSublayer:waveLayer];

        //创建水波纹layer2
        waveLayerTwo = [CAShapeLayer layer];
        waveLayerTwo.fillColor = [UIColor colorWithRed:3/255.f green:144/255.f blue:144/255.f alpha:0.7f].CGColor;
        [self.layer addSublayer:waveLayerTwo];

    }return self;
}



- (void)drawRect:(CGRect)rect{

    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawWaveLayer)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

}



- (void)drawWaveLayer{


    /*
     正弦型函数解析式:y=Asin(ωx+φ)+h

     各常数值对函数图像的影响:

     φ(初相位):决定波形与X轴位置关系或横向移动距离(左加右减)

     ω:决定周期(最小正周期T=2π/|ω|)

     A:决定峰值(即纵向拉伸压缩的倍数)

     h:表示波形在Y轴的位置关系或纵向移动距离(上加下减)

     */


    [self drawWaveLayerOne];

    [self drawWaveLayerTwo];



}

- (void)drawWaveLayerOne{
    //1.计算随着时间推移的X轴偏移量
    offsetX += speed;

    CGMutablePathRef path = CGPathCreateMutable();
    //起点
    CGPathMoveToPoint(path, nil, 0, offsetY);

    CGFloat y;
    CGFloat ω = 1.1*M_PI/waveWidth;
    CGFloat φ = offsetX*(M_PI/360.f);
    CGFloat h = offsetY;

    for (int x = 0; x <= waveWidth; x++) {
        y = A*sin(ω*x + (- φ)) + h*1;  //坐标系差异 需要转换 UIkit中 Y轴向下
        CGPathAddLineToPoint(path, nil, x, y);
    }

    //左下角点
    CGPathAddLineToPoint(path, nil, waveWidth, self.bounds.size.height);
    //右下角点
    CGPathAddLineToPoint(path, nil, 0, self.bounds.size.height);
    //闭合路径
    CGPathCloseSubpath(path);

    waveLayer.path = path;
    //释放
    CGPathRelease(path);

}

- (void)drawWaveLayerTwo{
    //1.计算随着时间推移的X轴偏移量
    offsetX += speed;

    CGMutablePathRef path = CGPathCreateMutable();
    //起点
    CGPathMoveToPoint(path, nil, 0, offsetY);
    CGFloat y;
    CGFloat ω = 1.1*M_PI/waveWidth;
    CGFloat φ = offsetX*(M_PI/270.f);
    CGFloat h = offsetY;

    for (int x = 0; x <= waveWidth; x++) {
        y = A*sin(ω*x + (- φ)) + h*1;  //坐标系差异 需要转换 UIkit中 Y轴向下
        CGPathAddLineToPoint(path, nil, x, y);
    }

    //左下角点
    CGPathAddLineToPoint(path, nil, waveWidth, self.bounds.size.height);
    //右下角点
    CGPathAddLineToPoint(path, nil, 0, self.bounds.size.height);
    //闭合路径
    CGPathCloseSubpath(path);

    waveLayerTwo.path = path;
    //释放
    CGPathRelease(path);
}


@end
帖子仅记录供以后自己翻阅,若有不懂请参看其他帖子的详细介绍
1、波纹动画主要依赖于CAShapeLayer的绘制,使用帧动画实现;需要使用多个CAShapeLayer通过y值变换组成(这里我只是用了2个CAShapeLayer)。 2、渐变色由CAGradientLayer完成。 ``` - (void)changeFirstWaveLayerPath { CGMutablePathRef path = CGPathCreateMutable(); CGFloat y = _wavePointY; CGPathMoveToPoint(path, nil, 0, y); for (float x = 0.0f; x <= _waveWidth; x ) { y = _waveAmplitude * 1.6 * sin((250 / _waveWidth) * (x * M_PI / 180) - _waveOffsetX * M_PI / 270) _wavePointY; CGPathAddLineToPoint(path, nil, x, y); } CGPathAddLineToPoint(path, nil, _waveWidth, 0); CGPathAddLineToPoint(path, nil, 0, 0); CGPathCloseSubpath(path); _shapeLayer1.path = path; CGPathRelease(path); } - (void)changeSecondWaveLayerPath { CGMutablePathRef path = CGPathCreateMutable(); CGFloat y = _wavePointY; CGPathMoveToPoint(path, nil, 0, y); for (float x = 0.0f; x <= _waveWidth; x ) { y = _waveAmplitude * 1.6 * sin((250 / _waveWidth) * (x * M_PI / 180) - _waveOffsetX * M_PI / 180) _wavePointY; CGPathAddLineToPoint(path, nil, x, y); } CGPathAddLineToPoint(path, nil, _waveWidth, 0); CGPathAddLineToPoint(path, nil, 0, 0); CGPathCloseSubpath(path); _shapeLayer2.path = path; CGPathRelease(path); } ``` 方法调用: ``` _waveOffsetX = _waveSpeed; [self changeFirstWaveLayerPath]; [self changeSecondWaveLayerPath]; [self.layer addSublayer:self.gradientLayer1]; self.gradientLayer1.mask = _shapeLayer1; [self.layer addSublayer:self.gradientLayer2]; self.gradientLayer2.mask = _shapeLayer2; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值