在工程中碰到了需要實現(xiàn)波浪動畫。只知道是使用正弦函數(shù)和余弦函數(shù)曹体,CADisplayLink來實現(xiàn)俗扇。
正弦,余弦函數(shù)就不多說了? y = Asin(ωx+φ) + k箕别,不同的參數(shù)控制正弦曲線的顯示效果铜幽。
A——振幅,當(dāng)物體作軌跡符合正弦曲線的直線往復(fù)運(yùn)動時串稀,其值為行程的1/2除抛。
(ωx+φ)——相位,反映變量y所處的狀態(tài)厨诸。
φ——初相镶殷,x=0時的相位禾酱;反映在坐標(biāo)系上則為圖像的左右移動微酬。
k——偏距,反映在坐標(biāo)系上則為圖像的上移或下移颤陶。
ω——角速度颗管, 控制正弦周期(單位角度內(nèi)震動的次數(shù))。
CADisplayLink 這個對象和 NSTimer 類似滓走,是一個定時觸發(fā)指定方法對象垦江,同樣也需要加入一個 NSRunLoop 內(nèi)才能持續(xù)執(zhí)行。
CADisplayLink 執(zhí)行的周期和 NSTimer 又不相同搅方,NSTimer 可以自定義周期比吭,而 CADisplayLink 是根據(jù)屏幕刷新周期為周期(1/60秒)
如下圖:
一、繪制靜態(tài)曲線
波浪效果其實說白了就是兩條移動的正余弦曲線姨涡,而繪制曲線則需要正余弦函數(shù)衩藤。
首先來看下不會動的波浪。
曲線可以看做一段段很短的直線連接起來繪制的赏表。
繪制直線則可以使用 Core Graphics 或 UIBezierPath 在 CAShapeLayer 來繪制检诗。
- (CAShapeLayer *)firstWavelayer {
?????????? if (!_firstWavelayer) {
???????????????? _firstWavelayer = [CAShapeLayer layer];
??????????????? _firstWavelayer.fillColor = [UIColor yellowColor].CGColor; // 填充色
??????????????? _firstWavelayer.strokeColor = [UIColor blueColor].CGColor; // 線的顏色
?????????? }
????????? return _firstWavelayer;
} // 懶加載一個 CAShapeLayer
繪制一條正弦曲線
- (void)drawFirstWave {
???????? _waveMoveFirst = _waveMoveFirst + 0.2;
??????? [self.layer addSublayer:self.firstWavelayer];
??????? CGMutablePathRef ref = CGPathCreateMutable();
??????? CGPathMoveToPoint(ref, nil, 0, self.frame.size.height);
// 根據(jù) y = Asin(ωx+φ) + k 的 x 變化來延展曲線,通過 φ 來移動曲線
??????? for (NSInteger i = 0; i <= self.frame.size.width ; i++) {
???????????? double y = 10 * sin(0.1 * i + _waveMoveFirst) + 10;
???????????? CGPathAddLineToPoint(ref, nil, i, y);
???????? }
//填充底部顏色
??????? CGPathAddLineToPoint(ref, nil, self.bounds.size.width,???????? self.bounds.size.height);
??????? CGPathAddLineToPoint(ref, nil, 0, self.bounds.size.height);
??????? CGPathCloseSubpath(ref);
??????? self.firstWavelayer.path = ref;
??????? CGPathRelease(ref);
}
通過以上代碼則繪制一條靜止的曲線瓢剿。
第二條曲線和第一條繪制代碼相同逢慌。
二、曲線動起來
要想曲線動起來根據(jù) y = Asin(ωx+φ) + k间狂,通過 φ 值的不斷變化來實現(xiàn)移動攻泼。
創(chuàng)建一個:
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(moveWave)];
NSRunLoop *runloop =? [NSRunLoop currentRunLoop];
[_displayLink addToRunLoop:runloop forMode:NSRunLoopCommonModes];
- (void)moveWave {
?????? [self drawFirstWave];
}
通過類型定時器 CADisplayLink 對象來 1/60 s 來執(zhí)行一次 drawFirstWave 方法來實現(xiàn) _waveMoveFirst 的值不斷變化,從而達(dá)到曲線運(yùn)動的效果鉴象。