示例:
示例.gif
思路:
使用貝塞爾曲線繪制正弦曲線;使用CAShapeLayer繪制形狀;使用CADisplayLink做刷屏;
CADisplayLink是一個能讓我們以和屏幕刷新率相同的頻率將內容畫到屏幕上的定時器。一但 CADisplayLink以特定的模式注冊到runloop之后,每當屏幕需要刷新的時候,runloop就會調用CADisplayLink綁定的target上的selector;iOS設備的刷新頻率事60HZ也就是每秒60次。那么每一次刷新的時間就是1/60秒 大概16.7毫秒;下面直接上代碼:
<br />
一. 創建THWave類,繼承于UIView
/** 浪寬: 一個完整的浪的寬度 */
@property (nonatomic, assign) CGFloat waveWidth;
/** 浪高: 波峰到波谷的距離 */
@property (nonatomic, assign) CGFloat waveHeight;
/** 浪速: 浪線的移動速度 */
@property (nonatomic, assign) CGFloat waveSpeed;
/** 浪速: 浪的內填充顏色 */
@property (nonatomic, strong) UIColor *waveColor;
/** 返回浪的Y點 */
@property (nonatomic, copy) WaveYBlock waveY;
/** 開始波動 */
- (void)startWaveAnimation;
/** 結束波動 */
- (void)endWaveAnimation;
二. 創建CAShapeLayer
#pragma mark - initUI
- (void)initUI{
// 設置底色
self.backgroundColor = [UIColor whiteColor];
// 創建layer
_waveLayer = [CAShapeLayer layer];
[self.layer addSublayer:_waveLayer];
}
#pragma mark - 設置浪高
- (void)setWaveHeight:(CGFloat)waveHeight{
_waveHeight = waveHeight;
CGRect frame = self.bounds;
frame.origin.y = frame.size.height - self.waveHeight;
frame.size.height = self.waveHeight;
_waveLayer.frame = frame;
}
#pragma mark - 設置浪色
- (void)setWaveColor:(UIColor *)waveColor{
_waveColor = waveColor;
_waveLayer.fillColor = waveColor.CGColor;
}
三. 創建刷屏器
#pragma mark - 開始和結束動畫
- (void)startWaveAnimation{
self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(wave)];
[self.timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)endWaveAnimation{
[self.timer invalidate];
self.timer = nil;
}
四. 繪制
// 動畫實現
- (void)wave{
// 1. 隨機
int speed = [@(self.waveSpeed) intValue];
int num = arc4random() % speed;
self.offset += num;
CGFloat width = self.bounds.size.width;
CGFloat height = self.waveHeight;
CGFloat y = 0.f;
// 2. 繪線
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, height)];
for (CGFloat x = 0.f; x <= width; x++) {
y = height * sinf(2*M_PI/self.waveWidth *x - self.offset * 0.0045);
[path addLineToPoint:CGPointMake(x, y)];
}
// 3. 返回x等于中心點時的Y值
CGFloat centerX = self.bounds.size.width / 2.0;
CGFloat centerY = height * sinf(2*M_PI/self.waveWidth * centerX - self.offset * 0.0045);
if (self.waveY) {
self.waveY(centerY);
}
// 4. 閉合曲線
[path addLineToPoint:CGPointMake(width, height)];
[path addLineToPoint:CGPointMake(0, height)];
[path closePath];
self.waveLayer.path = path.CGPath;
}
五. 外部引用,順便加條小船
#pragma mark - creatWave
-(void)creatWave{
// 1. view 增加浪
[self.view addSubview: ({
THWave *wave = [[THWave alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 300)];
wave.waveHeight = 18;
wave.waveSpeed = 15;
wave.waveWidth = 300;
wave.waveColor = [UIColor colorWithRed:48/255.0 green:204/255.0 blue:249/255.0 alpha:1];
// 2. 浪增加船
UIImageView *boat;
[wave addSubview:({
boat = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"boat"]];
boat.bounds = CGRectMake(0, 0, 123.3, 106.6);
boat.contentMode = UIViewContentModeScaleToFill;
boat;
})];
// 3. 弱化,調整船的位置
__weak typeof(self)weakSelf = self;
__weak typeof(wave)weakWave = wave;
wave.waveY = ^(CGFloat waveY){
CGRect frame = boat.bounds;
frame.origin.x = CGRectGetWidth(weakSelf.view.frame)/2.0 - CGRectGetWidth(frame)/2.0;
frame.origin.y = weakWave.bounds.size.height - boat.bounds.size.height - weakWave.waveHeight + waveY;
boat.frame = frame;
};
[wave startWaveAnimation];
wave;
})];
}
大功告成!!!
介紹一個強大的進度展示地址
https://github.com/ninjaprox/NVActivityIndicatorView
你也可以從這里看詳細的demo示例;