用drawRect以及CAReplicatorLayer绘制动态水波纹
用drawRect以及CAReplicatorLayer绘制动态水波纹
大大简化了写水波纹效果的难度,你可以根据示例自己组装水波纹效果,本设计是几个工具组合在一起完成的效果, DrawRectObject 以及 ReplicatorLineAnimationView 均可以独立完成更复杂的功能.
说明
1. 用sine计算正玄曲线
2. 用CAReplicatorLayer实现重复移动的效果
效果
源码
https://github.com/YouXianMing/UI-Component-Collection 中的 DrawRectObject
// // WaveView.h // DrawRectObject // // Created by YouXianMing on 16/8/1. // Copyright © 2016年 YouXianMing. All rights reserved. // #import "CustomDrawingView.h" typedef enum : NSUInteger { kStrokeWave = 1 << 2, kFillWave = 1 << 3 , } EWaveViewType; @interface WaveView : CustomDrawingView /** * Wave type, default is kFillWave. */ @property (nonatomic) EWaveViewType type; /** * Sine phase, default is 0. */ @property (nonatomic) CGFloat phase; /** * Wave crest height, Default is 10. */ @property (nonatomic) CGFloat waveCrest; /** * Full wave count, default is 1. */ @property (nonatomic) NSInteger waveCount; /** * The fill style. */ @property (nonatomic, strong) DrawingStyle *fillStyle; /** * The stroke style. */ @property (nonatomic, strong) DrawingStyle *strokeStyle; @end
// // WaveView.m // DrawRectObject // // Created by YouXianMing on 16/8/1. // Copyright © 2016年 YouXianMing. All rights reserved. // #import "WaveView.h" @implementation WaveView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.waveCrest = 10.f; self.waveCount = 1; self.phase = 0.f; self.type = kFillWave; DrawingStyle *fillStyle = [DrawingStyle new]; fillStyle.fillColor = [DrawingColor colorWithUIColor:[[UIColor redColor] colorWithAlphaComponent:0.5f]]; self.fillStyle = fillStyle; DrawingStyle *strokeStyle = [DrawingStyle new]; strokeStyle.strokeColor = [DrawingColor colorWithUIColor:[UIColor redColor]]; strokeStyle.lineWidth = 0.5f; self.strokeStyle = strokeStyle; } return self; } - (void)drawRect:(CGRect)rect { NSParameterAssert(self.fillStyle); NSParameterAssert(self.strokeStyle); [super drawRect:rect]; CGFloat width = self.frame.size.width; CGFloat height = self.frame.size.height; if (self.type & kFillWave) { [self.drawRectObject useDrawingStyle:_fillStyle drawFillBlock:^(DrawRectObject *drawRectObject) { for (CGFloat x = 0; x <= width; x++) { if (x == 0) { [drawRectObject moveToStartPoint:CGPointMake(x, _waveCrest * sin((2 * M_PI) * _waveCount / width * x + _phase) + height / 2.f)]; continue; } else { [drawRectObject addLineToPoint:CGPointMake(x, _waveCrest * sin((2 * M_PI) * _waveCount / width * x + _phase) + height / 2.f)]; } } [drawRectObject addLineToPoint:CGPointMake(width, height)]; [drawRectObject addLineToPoint:CGPointMake(0, height)]; [drawRectObject addLineToPoint:CGPointMake(0, _waveCrest * sin((2 * M_PI) * _waveCount / width * 0 + _phase) + height / 2.f)]; }]; } if (self.type & kStrokeWave) { [self.drawRectObject useDrawingStyle:_strokeStyle drawStrokeBlock:^(DrawRectObject *drawRectObject) { for (CGFloat x = 0; x <= width; x++) { if (x == 0) { [drawRectObject moveToStartPoint:CGPointMake(x, _waveCrest * sin((2 * M_PI) * _waveCount / width * x + _phase) + height / 2.f)]; continue; } else { [drawRectObject addLineToPoint:CGPointMake(x, _waveCrest * sin((2 * M_PI) * _waveCount / width * x + _phase) + height / 2.f)]; } } }]; } } @end
// // ViewController.m // DrawRectObject // // Created by YouXianMing on 16/7/30. // Copyright © 2016年 YouXianMing. All rights reserved. // #import "ViewController.h" #import "WaveView.h" #import "ReplicatorLineAnimationView.h" #import "UIView+SetRect.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Wave 1 { WaveView *waveView = [[WaveView alloc] initWithFrame:CGRectMake(0, 0, Width, Height)]; waveView.phase = 0.f; waveView.waveCrest = 5.f; waveView.waveCount = 1; waveView.type = kStrokeWave | kFillWave; { DrawingStyle *fillStyle = [DrawingStyle new]; fillStyle.fillColor = [DrawingColor colorWithUIColor:[[UIColor redColor] colorWithAlphaComponent:0.25f]]; waveView.fillStyle = fillStyle; DrawingStyle *strokeStyle = [DrawingStyle new]; strokeStyle.strokeColor = [DrawingColor colorWithUIColor:[[UIColor redColor] colorWithAlphaComponent:0.5f]]; strokeStyle.lineWidth = 0.5f; waveView.strokeStyle = strokeStyle; } ReplicatorLineAnimationView *replicatorLineView = [[ReplicatorLineAnimationView alloc] initWithFrame:waveView.bounds]; replicatorLineView.direction = kReplicatorLeft; replicatorLineView.speed = 0.1f; replicatorLineView.contentView = waveView; [replicatorLineView startAnimation]; [self.view addSubview:replicatorLineView]; } // Wave 2 { WaveView *waveView = [[WaveView alloc] initWithFrame:CGRectMake(0, 0, Width, Height)]; waveView.phase = 0.f; waveView.waveCrest = 10.f; waveView.waveCount = 1; waveView.type = kStrokeWave | kFillWave; { DrawingStyle *fillStyle = [DrawingStyle new]; fillStyle.fillColor = [DrawingColor colorWithUIColor:[[UIColor redColor] colorWithAlphaComponent:0.5f]]; waveView.fillStyle = fillStyle; DrawingStyle *strokeStyle = [DrawingStyle new]; strokeStyle.strokeColor = [DrawingColor colorWithUIColor:[UIColor redColor]]; strokeStyle.lineWidth = 0.5f; waveView.strokeStyle = strokeStyle; } ReplicatorLineAnimationView *replicatorLineView = [[ReplicatorLineAnimationView alloc] initWithFrame:waveView.bounds]; replicatorLineView.direction = kReplicatorLeft; replicatorLineView.speed = 0.3f; replicatorLineView.contentView = waveView; [replicatorLineView startAnimation]; [self.view addSubview:replicatorLineView]; } // Wave 3 { WaveView *waveView = [[WaveView alloc] initWithFrame:CGRectMake(0, 0, Width, Height)]; waveView.phase = 10.f; waveView.waveCrest = 15.f; waveView.waveCount = 1; waveView.type = kFillWave; { DrawingStyle *fillStyle = [DrawingStyle new]; fillStyle.fillColor = [DrawingColor colorWithUIColor:[UIColor redColor]]; waveView.fillStyle = fillStyle; } ReplicatorLineAnimationView *replicatorLineView = [[ReplicatorLineAnimationView alloc] initWithFrame:waveView.bounds]; replicatorLineView.direction = kReplicatorLeft; replicatorLineView.speed = 0.5f; replicatorLineView.contentView = waveView; [replicatorLineView startAnimation]; [self.view addSubview:replicatorLineView]; } } @end