先上效果图:
使用联通号码的朋友对此动画应该很熟悉,自从更新5.0版本后开始出现这个波纹的圆环,分析了一下实现原理,用的东西还不少,使我不得不把高中的数学知识再温习一遍,话说高中的数学知识都还给老师了,深感惭愧啊,波浪线使用的是正余弦函数:
正弦型函数解析式:y=Asin(ωx+φ)+b
各常数值对函数图像的影响:
φ:决定波形与X轴位置关系或横向移动距离(左加右减)
ω:决定周期(最小正周期T=2π/∣ω∣)
A:决定峰值(即纵向拉伸压缩的倍数)
b:表示波形在Y轴的位置关系或纵向移动距离(上加下减)
我们想绘制波纹图形,就要用正弦型函数解析式:y=Asin(ωx+φ)+b获取y坐标,将圆环放入坐标系中,并结合我们的手机屏幕的坐标;
圆环的直径相当于一个周期2M_PI,其y坐标为sinf(2 * M_PI / 直径 * x + self.offset * M_PI * 2 / 直径)
代码如下:
设置需显示的数据
- (void)setTitle:(NSString *)title num:(NSString *)num des:(NSString *)des recharge:(NSString *)recharge
{
self.firstLayer.fillColor = self.firstColor.CGColor;
self.secondLayer.fillColor = self.secondColor.CGColor;
[self setContent];
_titleL.text = title;
_numL.text = num;
_desL.text = des;
[_rechargeB setTitle:recharge forState:UIControlStateNormal];
_height = self.bounds.size.height * (1 - self.progress);
[self stopWave];
[self startWave];
}
- (void)startWave
{
self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(waveAnimation)];
[self.timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
看到CADisplayLink你可能会感觉到陌生,CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器。当创建一个新的CADisplayLink对象并把它添加到一个runloop中,当CADisplayLink以特定的模式注册到runloop之后,每当屏幕需要刷新的时候,runloop就会调用CADisplayLink绑定的target的selector,这时target可以读到CADisplayLink的每次调用的时间戳,用来准备下一帧显示需要的数据。
绘制波纹路径的代码:
- (void)waveAnimation
{
CGFloat waveHeight = self.waveRange;
if (self.progress == 0.0f || self.progress == 1.0f) {
waveHeight = 0.f;
}
self.offset += self.rate;
//第一条波纹路径
CGMutablePathRef pathRef = CGPathCreateMutable();
CGFloat startOffY = waveHeight * sinf(self.offset * M_PI * 2 / self.bgview.bounds.size.width);
CGFloat orignOffY = 0.0;
CGPathMoveToPoint(pathRef, NULL, 0, startOffY);
for (CGFloat i = 0.f; i <= self.bgview.bounds.size.width; i++) {
orignOffY = waveHeight * sinf(2 * M_PI / self.bgview.bounds.size.width * i + self.offset * M_PI * 2 / self.bgview.bounds.size.width) + self.height;
CGPathAddLineToPoint(pathRef, NULL, i, orignOffY);
}
CGPathAddLineToPoint(pathRef, NULL, self.bgview.bounds.size.width, orignOffY);
CGPathAddLineToPoint(pathRef, NULL, self.bgview.bounds.size.width, self.bgview.bounds.size.height);
CGPathAddLineToPoint(pathRef, NULL, 0, self.bgview.bounds.size.height);
CGPathAddLineToPoint(pathRef, NULL, 0, startOffY);
CGPathCloseSubpath(pathRef);
self.firstLayer.path = pathRef;
CGPathRelease(pathRef);
//第二条波纹路径
CGMutablePathRef pathRef1 = CGPathCreateMutable();
CGFloat startOffY1 = waveHeight * sinf(self.offset * M_PI * 2 / self.bgview.bounds.size.width);
CGFloat orignOffY1 = 0.0;
CGPathMoveToPoint(pathRef1, NULL, 0, startOffY1);
for (CGFloat i = 0.f; i <= self.bgview.bounds.size.width; i++) {
orignOffY1 = waveHeight * cosf(2 * M_PI / self.bgview.bounds.size.width * i + self.offset * M_PI * 2 / self.bgview.bounds.size.width) + self.height;
CGPathAddLineToPoint(pathRef1, NULL, i, orignOffY1);
}
CGPathAddLineToPoint(pathRef1, NULL, self.bgview.bounds.size.width, orignOffY1);
CGPathAddLineToPoint(pathRef1, NULL, self.bgview.bounds.size.width, self.bgview.bounds.size.height);
CGPathAddLineToPoint(pathRef1, NULL, 0, self.bgview.bounds.size.height);
CGPathAddLineToPoint(pathRef1, NULL, 0, startOffY1);
CGPathCloseSubpath(pathRef1);
self.secondLayer.path = pathRef1;
CGPathRelease(pathRef1);
}
对于圆环内的label等控件,使用Masonry进行布局即可,这里就不过多对Masonry进行说明,以上就是根据中国联通手机营业厅首页圆滑进行的仿写,有哪些不足之处请大家提出。