Untitled.gif
不說廢話直接上代碼
#import <UIKit/UIKit.h>
@interface JDWaterWaveView : UIView
/**
水紋速度
*/
@property(nonatomic,assign)CGFloat waveSpeed;
/**
水紋振幅
*/
@property(nonatomic,assign)CGFloat waveA;
/**
水紋周期
*/
@property(nonatomic,assign)CGFloat waveW;
/**
頁面退出的時(shí)候必須調(diào)用,否則定時(shí)器無法銷
*/
- (void)stopWave;
@end
#import "JDWaterWaveView.h"
@interface JDWaterWaveView ()
/**
位移
*/
@property(nonatomic,assign)CGFloat offsetX;
/**
當(dāng)前波浪高度
*/
@property(nonatomic,assign)CGFloat currentK;
/**
波浪寬度
*/
@property(nonatomic,assign)CGFloat waterWaveWidth;
@property(nonatomic,retain)CAShapeLayer *waveLayer; //
@property(nonatomic,retain)CADisplayLink *waveDisplaylink; //定時(shí)器(與屏幕刷新頻率一致)
@end
@implementation JDWaterWaveView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_waveLayer =[[CAShapeLayer alloc]init];
_waveA = 10;
_waveW = (2 * M_PI) / self.bounds.size.width;
_offsetX = 0;
_currentK = self.bounds.size.height / 2;;
_waveSpeed = 0.05;
_waterWaveWidth =self.sizeWidth;
[self addLayer];
}
return self;
}
- (void)addLayer {
//設(shè)置閉環(huán)顏色
_waveLayer.fillColor =JDRGBColor(73, 142, 178, 0.5).CGColor;
//設(shè)置邊緣線的顏色
//_firstWaveLayer.strokeColor =[UIColor blueColor].CGColor;
//們可以對繪制的Path進(jìn)行分區(qū)检疫。這兩個屬性的值在0~1之間巴粪,0代表Path的開始位置平项,1代表Path的結(jié)束位置。是一種線性遞增關(guān)系。strokeStart默認(rèn)值為0吴侦,strokeEnd默認(rèn)值為1。這兩個屬性都支持動畫。
//_firstWaveLayer.strokeStart = 0.0;
//_firstWaveLayer.strokeEnd = 0.8;
[self.layer addSublayer:_waveLayer];
//CADisplayLink是一個能讓我們以和屏幕刷新率相同的頻率將內(nèi)容畫到屏幕上的定時(shí)器碾盐。
_waveDisplaylink =[CADisplayLink displayLinkWithTarget:self selector:@selector(getCurrentWave)];
[_waveDisplaylink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)getCurrentWave {
_offsetX += _waveSpeed;
[self setCurrentFirstWaveLayerPath];
}
- (void)setCurrentFirstWaveLayerPath {
//創(chuàng)建一個路徑
CGMutablePathRef path = CGPathCreateMutable();
CGFloat y = _currentK;
CGPathMoveToPoint(path, NULL, 0, y);
for (CGFloat i =0; i<_waterWaveWidth; i++) {
y =_waveA *sin(_waveW * i + _offsetX)+_currentK;
CGPathAddLineToPoint(path, NULL, i, y);
}
CGPathAddLineToPoint(path, NULL, _waterWaveWidth, self.sizeHeight);
CGPathAddLineToPoint(path, NULL, 0, self.sizeHeight);
_waveLayer.path =path;
//一定要加上這句,否則會有內(nèi)存泄露
CGPathRelease(path);
}
- (void)stopWave{
[_waveDisplaylink invalidate];
_waveDisplaylink = nil;
}
-(void)dealloc
{
}
@end
其中包括兩個坑:
1>在setCurrentFirstWaveLayerPath
這個方法中,由于使用到了CGMutablePathRef path = CGPathCreateMutable();
所以務(wù)必使用CGPathRelease(path);釋放,否則會造成內(nèi)存不斷增加的問題
2>定時(shí)器CADisplayLink 循環(huán)引用導(dǎo)致無法執(zhí)行 dealloc
所以務(wù)必在調(diào)用此 view 的界面退出的時(shí)候,執(zhí)行 stopWave 方法,銷毀定時(shí)器
- (void)stopWave{
[_waveDisplaylink invalidate];
_waveDisplaylink = nil;
}
當(dāng)然第二種方法也有別的解決方法比如
http://www.cnblogs.com/tingxins/p/6034407.html
但是我覺得有點(diǎn)麻煩了,所以采用了一種簡單但是容易忽略的方式.看個人習(xí)慣了
后續(xù)更新:最合適的解決方式->
http://www.reibang.com/p/f558ce05b14f
Demo地址:https://github.com/yuying2012/WJDStudyLibrary
這是一個大工程,請從工程中尋找相關(guān)模塊代碼.