贴代码之前我们先了解一下CAShaperLayer吧
首先这是一个遮罩类,这个东西是画出来的,是一个闭合的曲线,我门可以用这个类来对view来进行各种变形,闭合的区域外都是透明的,根据这个特性,我们就可以来浪了
补充知识:首先你要知道啥事正弦函数,就是sin,上过高中的,听过课的应该都知道这玩应是干啥的,就一个起点是(0,0)的浪,依稀的记得好像还有个圆一转,就出来了,法科!忘记了,自行google。
正弦波浪公式:y=Asin(ωx+φ)+k
-A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2
-ω——角速度, 控制正弦周期(单位角度内震动的次数)
-φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动
-k——偏距,反映在坐标系上则为图像的上移或下移
--------------------------脱裤子,入正题--------------------------
我写的是一个视图
需要的类
CAShapeLayer:遮罩
CADisplayLink :这个东西跟定时器一样,不过这个东西是在target没刷新1帧才执行一次,所以NSTimer 用起来是不准确的
需要的属性
@property (nonatomic, strong) CAShapeLayer *waveShapeLayerA; //?< 遮罩
@property (nonatomic, strong) CAShapeLayer *waveShapeLayerB; //?< 另外一个遮罩
@property (nonatomic, strong) UIColor *waveColor; //?< 颜色
@property (nonatomic, strong) CADisplayLink *displayLink; //?< 定时器
@property (nonatomic, assign) CGFloat offsetX; //?< A相位
@property (nonatomic, assign) CGFloat offsetXB; //?< B相位
@property (nonatomic, assign) CGFloat waveWidth; //?< 浪的宽度
@property (nonatomic, assign) CGFloat waveAmplitude; //?< 振幅
@property (nonatomic, strong) UIView *back; //?< 另外一个颜色的视图
//下面这两个我方.h里面了
@property (nonatomic, assign) CGFloat waveHeight;
@property (nonatomic, assign) CGFloat waveSpeed;
(void)wave;
初始化变量
- (void)layoutSubviews
{
_offsetX = 0;
_offsetXB = M_PI/2.0; //让第2个layer移动1/4个周期
_waveSpeed = 0.03;
_waveHeight = 30;
_waveWidth = self.frame.size.width;
_waveAmplitude = 10;
}
让它动
这里创建了两个CAShaperLayer,一个给self 另一个给加在self上的另外一个视图
- (void)wave {
/*
*创建两个layer
*/
self.waveColor = [UIColor colorWithRed:((arc4random() % 255)/244.0) green:((arc4random() % 255)/244.0) blue:((arc4random() % 255)/244.0) alpha:0.3];
self.waveShapeLayerA = [CAShapeLayer layer];
self.waveShapeLayerA.fillColor = self.waveColor.CGColor;
[self.layer addSublayer:self.waveShapeLayerA];
_back = [[UIView alloc]initWithFrame:self.bounds];
[self addSubview:_back];
self.waveShapeLayerB = [CAShapeLayer layer];
self.waveShapeLayerB.fillColor = [UIColor blueColor].CGColor;
[self.back.layer addSublayer:self.waveShapeLayerB];
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(getCurrentWave)];
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
核心的东西
这里主要是公式,然后通过x得到所有Y的点绘制成一个闭合的曲线,需要两个,因为我们是两个浪
- (void)getCurrentWave {
//offsetX决定x位置,如果想搞明白可以多试几次
self.offsetX += self.waveSpeed;
//声明第一条波曲线的路径
CGMutablePathRef path = CGPathCreateMutable();
//设置起始点
CGPathMoveToPoint(path, nil, 0, self.waveHeight);
CGFloat y = 0.f;
//第一个波纹的公式
for (float x = 0.f; x <= self.waveWidth ; x++) {
y = self.waveAmplitude * sin((300 / self.waveWidth) * (x * M_PI / 180) - self.offsetX) + self.waveHeight;
CGPathAddLineToPoint(path, nil, x, y);
x++;
}
//把绘图信息添加到路径里
CGPathAddLineToPoint(path, nil, self.waveWidth, self.frame.size.height);
CGPathAddLineToPoint(path, nil, 0, self.frame.size.height);
//结束绘图信息
CGPathCloseSubpath(path);
self.waveShapeLayerA.path = path;
//释放绘图路径
CGPathRelease(path);
/*
* 第二个
*/
self.offsetXB += self.waveSpeed;
CGMutablePathRef pathT = CGPathCreateMutable();
CGPathMoveToPoint(pathT, nil, 0, self.waveHeight+100);
CGFloat yT = 0.f;
for (float x = 0.f; x <= self.waveWidth ; x++) {
yT = self.waveAmplitude * sin((300 / self.waveWidth) * (x * M_PI / 180) - self.offsetXB) + self.waveHeight;
CGPathAddLineToPoint(pathT, nil, x, yT);
}
CGPathAddLineToPoint(pathT, nil, self.waveWidth, self.frame.size.height);
CGPathAddLineToPoint(pathT, nil, 0, self.frame.size.height);
CGPathCloseSubpath(pathT);
self.waveShapeLayerB.path = pathT;
CGPathRelease(pathT);
}
基本完成
稍作修饰,就可以出锅了!这里我用了两个slider 分别控制高度 和速度,别的变量也可以。
- (void)viewDidLoad {
[super viewDidLoad];
_wave = [[WaveView alloc]initWithFrame:CGRectMake(50, 400, 300, 300)];
[self.view addSubview:_wave];
_wave.layer.masksToBounds = YES;
_wave.layer.cornerRadius = 150;
[_wave wave];
_wave.backgroundColor = [UIColor colorWithRed:((arc4random() % 255)/244.0) green:((arc4random() % 255)/244.0) blue:((arc4random() % 255)/244.0) alpha:0.3];
}
- (IBAction)change:(UISlider *)sender {
CGFloat value = (sender.value * 150);
_wave.waveHeight = value;
}
- (IBAction)speed:(UISlider *)sender {
CGFloat value = (sender.value * 0.1);
_wave.waveSpeed = value;
}
结构层次
我们可以看到,两个view分别用layer来实现波浪,这样就双波浪了(好像废话)