1:实现原理:两条不同内填充色的波浪向相对方向平移,产生波动效果,使用的技术:CAShapeLayer,UIBezierPath
2:实现效果
3:实现步骤:
画两条贝塞尔曲线,由于需要交叉产生效果,当前屏幕和屏幕外相同宽度的部分画线,然后按照固定的速度移动,每到移动到屏幕边缘的时候重新设置波浪线的路径,波浪的交叉重贴的部分产生的效果就是锁需要的效果具体实现代码如下:
#import <UIKit/UIKit.h>
@interface WaveView : UIView
- (void)startWave;
@end
#import "WaveView.h"
#import "UIColor+Util.h"
@interface WPoint : NSObject
@property(nonatomic)CGFloat x;
@property(nonatomic)CGFloat y;
- (instancetype)initWithX:(CGFloat)x y:(CGFloat)y;
@end
@implementation WPoint
- (instancetype)initWithX:(CGFloat)x y:(CGFloat)y
{
self = [super init];
if (self) {
_x = x;
_y = y;
}
return self;
}
@end
@interface WaveView ()
{
float mViewWidth,mLevelLine,mWaveHeight,mWaveWidth,mLeftSide,mRightSide,mMoveLen,mMoveLen1;
int mViewHeight;
float speed;//水波平移速度
float speedX;//每次平移在x轴的距离
int speedWave;//移动时间,time的调用时间
NSMutableArray<WPoint *> *mPointsList;
NSMutableArray<WPoint *> *mPointsList1;
CAShapeLayer *mPaint;
CAShapeLayer *mPaint1;
UIBezierPath *mWavePath;
UIBezierPath *mWavePath1;
BOOL isMeasured;
NSTimer *timer;
}
@end
@implementation WaveView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
mPointsList = [NSMutableArray new];
mPointsList1= [NSMutableArray new];
mWaveHeight = 20;
mWaveWidth = 200;
speed = 0.8f;
speedX = 0.8f;
speedWave = 0.8;
isMeasured = false;
mPaint = [CAShapeLayer new];
mPaint.fillColor = [UIColor colorWithHexString:@"#DFF2FF"].CGColor;
mPaint.contentsScale = [[UIScreen mainScreen] scale];
mPaint1 = [CAShapeLayer new];
mPaint1.fillColor = [UIColor colorWithHexString:@"#ffffff"].CGColor;
mPaint1.contentsScale = [[UIScreen mainScreen] scale];
mWavePath = [UIBezierPath new];
mWavePath1 = [UIBezierPath new];
[self.layer addSublayer:mPaint];
[self.layer addSublayer:mPaint1];
}
return self;
}
#pragma mark-----绘图------
- (void)drawRect:(CGRect)rect{
[mWavePath1 removeAllPoints];
int j = 5;
WPoint *point = [mPointsList objectAtIndex:8];
[mWavePath1 moveToPoint:CGPointMake(point.x, point.y)];
for (; j >= -1; j = j - 2){
WPoint *point1 = [mPointsList objectAtIndex:j + 1];
WPoint *point2 = [mPointsList objectAtIndex:j + 2];
[mWavePath1 addQuadCurveToPoint:CGPointMake(point1.x, point1.y) controlPoint:CGPointMake(point2.x, point2.y)];
}
WPoint *point3 = [mPointsList objectAtIndex:0];
[mWavePath1 addLineToPoint:CGPointMake(point3.x, mViewHeight)];
[mWavePath1 addLineToPoint:CGPointMake(mRightSide, mViewHeight)];
[mWavePath1 closePath];
mPaint1.path = mWavePath1.CGPath;
[mWavePath removeAllPoints];
int i = 0;
WPoint *point4 = [mPointsList1 objectAtIndex:0];
[mWavePath moveToPoint:CGPointMake(point4.x, point4.y)] ;
for (; i < mPointsList1.count - 2; i = i + 2) {
WPoint *point5 = [mPointsList1 objectAtIndex:i + 2];
WPoint *point6 = [mPointsList1 objectAtIndex:i + 1];
[mWavePath addQuadCurveToPoint:CGPointMake(point5.x, point5.y) controlPoint:CGPointMake(point6.x, point6.y)];
}
WPoint *point7 = [mPointsList1 objectAtIndex:8];
[mWavePath addLineToPoint:CGPointMake(point7.x, mViewHeight)];
[mWavePath addLineToPoint:CGPointMake(mLeftSide, mViewHeight)];
[mWavePath closePath];
//mPaint的Style是FILL,会填充整个Path区域
mPaint.path = mWavePath.CGPath;
}
#pragma mark---开始和结束动画------
- (void)startWave{
if (!timer) {
[timer invalidate];
timer = nil;
}
timer = [NSTimer timerWithTimeInterval:speedWave target:self selector:@selector(updateHandler) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)layoutSubviews
{
if (!isMeasured) {
CGSize size = self.frame.size;
isMeasured = true;
mViewHeight = size.height;
mViewWidth = size.width/4.0f;
mLevelLine = mViewHeight / 2;
// 根据View宽度计算波形峰值
mWaveHeight = mViewWidth / 10.0f;
// 波长等于四倍View宽度也就是View中只能看到四分之一个波形,这样可以使起伏更明显
mWaveWidth = mViewWidth * 4;
// 左边隐藏的距离预留一个波形
mLeftSide = -mWaveWidth;
mRightSide = mWaveWidth*2;
// 这里计算在可见的View宽度中能容纳几个波形,注意n上取整
int n = (int) ceil(mViewWidth / mWaveWidth + 0.5);
// n个波形需要4n+1个点,但是我们要预留一个波形在左边隐藏区域,所以需要4n+5个点
for (int i = 0; i < (4 * n + 5); i++){
// 从P0开始初始化到P4n+4,总共4n+5个点
float x = i * mWaveWidth / 4 - mWaveWidth;
float y = 0;
switch (i % 4){
case 0:
case 2:
// 零点位中线上
y = mLevelLine;
break;
case 1:
// 往下波动的控制点
y = mLevelLine + mWaveHeight;
break;
case 3:
// 往上波动的控制点
y = mLevelLine - mWaveHeight;
break;
}
[mPointsList addObject:[[WPoint alloc]initWithX:x y:y]];
[mPointsList1 addObject:[[WPoint alloc]initWithX:x y:y]];
}
//----将第一条波纹翻转----点上下颠倒-----
int h=1;
for (int t=1;t<mPointsList1.count;t=t+2){
WPoint *point = [mPointsList1 objectAtIndex:t];
if (h%2==1){
point.y = point.y - mWaveHeight*2;
}else {
point.y = point.y + mWaveHeight*2;
}
h++;
}
//---第二条波纹移动到屏幕右边------
for (int x=0;x<mPointsList.count;x++){
WPoint *point = [mPointsList objectAtIndex:x];
point.x =point.x + mWaveWidth;
}
}
}
- (void)stopWaveLine{
if (!timer) {
[timer invalidate];
timer = nil;
}
}
- (void)updateHandler{
// 记录平移总位移
mMoveLen += speed;
mMoveLen1 += speedX;
if (mLevelLine < mViewHeight/2)
mLevelLine = mViewHeight/2;
mLeftSide += speed;
mRightSide -= speedX;
// 波形平移
for (int i = 0; i < mPointsList.count; i++){
WPoint *point = [mPointsList objectAtIndex:i];
point.x -= speed;
}
for (int i = 0; i < mPointsList1.count; i++){
WPoint *point = [mPointsList1 objectAtIndex:i];
point.x += speedX;
}
if (mMoveLen >= mWaveWidth){
// 波形平移超过一个完整波形后复位
mMoveLen = 0;
[self resetPoints];
}
if (mMoveLen1 >= mWaveWidth) {
// 波形平移超过一个完整波形后复位
mMoveLen1 = 0;
[self resetPoints1];
}
[self setNeedsDisplay];
}
#pragma mark--------重置关键点----
- (void)resetPoints{
mLeftSide = -mWaveWidth;
for (int i = 0; i < mPointsList1.count; i++){
WPoint *pointValue = [mPointsList1 objectAtIndex:i];
pointValue.x = i * mWaveWidth / 4 - mWaveWidth;
}
}
- (void)resetPoints1{
mRightSide = mWaveWidth*2;
for (int i = 0; i < mPointsList.count; i++){
WPoint *pointValue = [mPointsList objectAtIndex:i];
pointValue.x = i * mWaveWidth / 4;
}
}
@end
3:使用:
WaveView *waveView = [[WaveView alloc]initWithFrame:self.view.bounds];
[waveView setBackgroundColor:[UIColor colorWithHexString:@"#48DEBF"]];
[self.view addSubview:waveView];
[waveView startWave];