- 前言:現(xiàn)在很多app為了提供好的交互效果給用戶,通常都會通過添加動畫效果來達到目的头岔。一個好的動畫效果往往會起到神來之筆的作用三痰。而在IOS中動畫效果也是豐富多彩的,我準備在后續(xù)的筆記中詳細的記錄那些動畫。
- 今天我們就來實現(xiàn)一下在IOS中的水波動畫论泛。先上效果圖:
-
最開始看到這個效果確實有點難的职恳,不過如果對正弦公式比較了解的話實現(xiàn)起來也挺簡單的所禀。
高中知識:y = Asin(wx + θ) + k;
其中A:代表振幅; w:角頻率,和周期的關(guān)系是:T = 2π/|w| ;θ:初相,相對于標準的正弦公式y(tǒng) = sin(x)而言,θ代表
標準的正弦公式y(tǒng) = sin(x)在水平(x軸)方向上的整體移動放钦,即左加右減;k:偏距,代表標準的正弦公式y(tǒng) = sin(x)在 垂直(y軸)方向上的整體移動,即上加下減北秽。
由表達式 y = sin(x)我們知道:在[0,2π]的區(qū)間上繪制一個完整的正弦波形,周期剛好是2π(T= 2π/|w|) 這里w = 1;繪制2個完整的正弦波形,周期為π。所以可以把w理解成完整波形的個數(shù)最筒。由此可以得出:在區(qū)間[0,waveWidth]上繪制n個完整的波形,w = 2π * n / waveWidth贺氓。另外還要注意一點就是UIKit框架坐標軸是向下的。
上面的知識也只是對正弦公式進行回顧床蜘。怎么樣才能得到波形效果呢辙培?關(guān)鍵點就在初相θ身上。
-
下面這張圖是正弦公式:y = sin(x)的圖譜:
我們把初相θ向左移動1個單位長度得到公式:y = sin(x + 1)的圖譜:
比較這兩張圖譜邢锯,我們可以從中發(fā)現(xiàn):要想實現(xiàn)波形震蕩效果扬蕊,我們只需不斷變化初相θ的值,然后不斷刷新屏幕即可丹擎。
CADisplayLink:這個定時器的刷新頻率是60HZ尾抑,即每秒可以對屏幕進行60次刷新,我們?nèi)庋凼歉杏X不出刷新間隔的時差的。
整個實現(xiàn)過程的代碼如下:
@interface JGWaterWaveAnimation()
{
//振幅--這個決定波形的起伏高度
CGFloat _waterAmplitude;
//頻率--這個決定波形的寬度
CGFloat _waterFrequency;
//初相:這個決定了波形水平移動的速度
CGFloat _waterEpoch;
//偏距--調(diào)節(jié)距離頂部的高度
CGFloat _waterSetover;
//定時器
CADisplayLink *_timer;
//波形整個的寬度
CGFloat _waterWaveWidth;
//波形的整個高度
CGFloat _waterWaveHeight;
}
/**layer*/
@property(strong,nonatomic)CAShapeLayer *waterShapeLayer;
@end
@implementation JGWaterWaveAnimation
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
//default
_waterAmplitude = 15.0;
//假設(shè)在frame的長度上出現(xiàn)3個完整的波形:注意這里乘以0.5出現(xiàn)震蕩效果,如果不乘以0.5只會出現(xiàn)波形平移的效果。
_waterFrequency = 2 *M_PI * 3 / frame.size.width *0.5;
_waterEpoch = 0.0;
_waterSetover = 20.0;
_waterWaveWidth = CGRectGetWidth(self.frame);
_waterWaveHeight = CGRectGetHeight(self.frame);
[self.layer addSublayer:self.waterShapeLayer];
//初始化定時器
_timer = [CADisplayLink displayLinkWithTarget:[YYWeakProxy proxyWithTarget:self] selector:@selector(waterWaveAnimation)];
[_timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
return self;
}
- (void)waterWaveAnimation{
//核心代碼:
_waterEpoch += 0.08;
//path
UIBezierPath *waterWavePath = [UIBezierPath bezierPath];
[waterWavePath moveToPoint:CGPointMake(0, 0)];
for (CGFloat x = 0; x < _waterWaveWidth; x ++) {
CGFloat y = _waterAmplitude * sinf(_waterFrequency * x + _waterEpoch) + _waterSetover;
[waterWavePath addLineToPoint:CGPointMake(x, y)];
}
[waterWavePath addLineToPoint:CGPointMake(_waterWaveWidth, _waterWaveHeight)];
[waterWavePath addLineToPoint:CGPointMake(0, _waterWaveHeight)];
[waterWavePath closePath];
self.waterShapeLayer.path = waterWavePath.CGPath;
}
- (CAShapeLayer *)waterShapeLayer{
if (!_waterShapeLayer) {
_waterShapeLayer = [CAShapeLayer layer];
_waterShapeLayer.frame = self.bounds;
_waterShapeLayer.fillColor = [UIColor colorWithRed:52/255.0 green:152/255.0 blue:219/255.0 alpha:1.0].CGColor;
_waterShapeLayer.strokeColor = [UIColor clearColor].CGColor;
}
return _waterShapeLayer;
}
- (void)dealloc{
[_timer invalidate];
_timer = nil;
}
@end
原文:https://blog.csdn.net/h2282802627/article/details/79116601