iOS绘制波浪,具体来说就是结合CAShaperLayer、UIBezierPath进行一个高性能的绘制。前文已经说过这两者是如何可以进行高性能绘制,这里不再赘述。
具体需要先了解正弦曲线的公式,初中数学,我给贴过来了。
正弦曲线可表示为y=Asin(ωx+φ)+k,定义为函数y=Asin(ωx+φ)+k在直角坐标系上的图象,其中sin为正弦符号,x是直角坐标系x轴上的数值,y是在同一直角坐标系上函数对应的y值,k、ω和φ是常数(k、ω、φ∈R且ω≠0)
A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
(ωx+φ)——相位,反映变量y所处的状态。
φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
k——偏距,反映在坐标系上则为图像的上移或下移。
ω——角速度, 控制正弦周期(单位弧度内震动的次数)。
先看效果吧,懒得录制gif了,静态图凑合看吧,有兴趣的可以下载demo查看。
封装了一个WaterWave的类,使用很简单:
#import "ViewController.h"
#import "WaterWave.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet WaterWave *waveView;
@end
@implementation ViewController
#pragma mark - event
- (IBAction)startWave:(id)sender {
[self. waveView startWave];
}
- (IBAction)pauseWave:(id)sender {
[self.waveView pauseWave];
}
@end
WaterWave类:
#import <UIKit/UIKit.h>
@interface WaterWave : UIView
@property (nonatomic, strong, nullable)UIColor *waveColor; // 波浪颜色
/**
default is 0.7 [0,1]
*/
@property (nonatomic, assign)CGFloat percent; // 波浪百分比
- (void)startWave;
- (void)pauseWave;
- (void)removeWave;
@end
//
// WaterWave.m
// WaterWave
//
// Created by wu on 2018/8/7.
// Copyright © 2018年 wu. All rights reserved.
//
#import "WaterWave.h"
@interface WaterWave ()
@property (nonatomic, strong) CADisplayLink *waveDisplayLink;
@property (nonatomic, strong) CAShapeLayer *waveLayer;
@property (nonatomic, assign) CGFloat waveAmplitude; // 波纹振幅
@property (nonatomic, assign) CGFloat waveCycle; // 波纹周期
@property (nonatomic, assign) CGFloat waveSpeed; // 波纹速度
@property (nonatomic, assign) CGFloat waveWidth; // 波纹宽度
@property (nonatomic, assign) CGFloat xOffset; // 正弦曲线的初相,反映出在x轴上的移动,
@property (nonatomic, assign) CGFloat originWavePointY;
@end
@implementation WaterWave
#pragma mark - init
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
[self startWave];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setup];
[self startWave];
}
return self;
}
- (void)setup
{
self.waveColor = [UIColor cyanColor];
self.percent = 0.7;
self.waveSpeed = 0.1/M_PI;
self.waveWidth = CGRectGetWidth(self.frame);
self.xOffset = 0;
self.waveAmplitude = 15;
self.originWavePointY = CGRectGetHeight(self.frame) * (1-_percent);
self.waveCycle = 1.29 * M_PI / self.waveWidth;
}
#pragma mark - public
- (void)startWave
{
if (!_waveLayer) {
[self.layer addSublayer:self.waveLayer];
}
[self.waveDisplayLink setPaused:NO];
}
- (void)pauseWave
{
[self.waveDisplayLink setPaused:YES];
}
- (void)removeWave
{
[self.waveDisplayLink invalidate];
[self.waveLayer removeFromSuperlayer];
self.waveDisplayLink = nil;
self.waveLayer = nil;
}
- (void)setPercent:(CGFloat)percent
{
_percent = (percent >0 && percent <= 1) ? percent : _percent;
}
#pragma mark - event
- (void)changeWave:(CADisplayLink *)displayLink
{
self.xOffset -= self.waveSpeed;
UIBezierPath *sinPath = [UIBezierPath bezierPath];
CGFloat sinY = self.originWavePointY;
[sinPath moveToPoint:CGPointMake(0, sinY)];
for (float x = 0.0f; x <= self.waveWidth; x++) {
// 正弦波浪
sinY = self.waveAmplitude * sin(self.waveCycle * x + self.xOffset) + self.originWavePointY;
[sinPath addLineToPoint:CGPointMake(x, sinY)];
}
[sinPath addLineToPoint:CGPointMake(self.waveWidth, CGRectGetHeight(self.frame))];
[sinPath addLineToPoint:CGPointMake(0, self.frame.size.height)];
[sinPath closePath];
self.waveLayer.path = sinPath.CGPath;
}
#pragma mark - getter
- (CAShapeLayer *)waveLayer
{
if (!_waveLayer) {
_waveLayer = [CAShapeLayer layer];
_waveLayer.fillColor = _waveColor.CGColor;
}
return _waveLayer;
}
- (CADisplayLink *)waveDisplayLink
{
if (!_waveDisplayLink) {
_waveDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeWave:)];
[_waveDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
return _waveDisplayLink;
}
@end
有问题的可以一起沟通,也欢迎指正代码存在的错误和不严谨之处。
网友评论