iOS 动画篇 (三) CADisplayLink与CoreGraphics实现动画
本文主要介绍利用CoreGraphics和CADisplayLink来实现一个注水动画。来一个效果图先:
在介绍注水动画前,先介绍利用CoreGraphics实现进度条的绘制。
一、扇形进度绘制
效果:
代码如下:
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
self.arcColor = [UIColor cyanColor];
}
return self;
} - (void)drawRect:(CGRect)rect {
[super drawRect:rect]; CGContextRef context = UIGraphicsGetCurrentContext(); [self.arcColor setFill]; CGFloat startAngle = -M_PI_2;
CGFloat endAngle = self.progress * M_PI * + startAngle; CGPoint center = CGPointMake(rect.size.width / , rect.size.height / ); UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:rect.size.width / startAngle:startAngle endAngle:endAngle clockwise:YES]; CGContextAddPath(context, path.CGPath);
CGContextAddLineToPoint(context, center.x, center.y); CGContextDrawPath(context, kCGPathFill);
} - (void)setProgress:(CGFloat)progress
{
NSLog(@"%g", progress);
if (progress > ) {
progress = ;
}else if (progress < ){
progress = ;
}
_progress = progress;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsDisplay];
});
}
原理就是根据不同的进度值不停的重新绘制扇形。
二、绘制带边缘的扇形进度图
代码如下:
@implementation ArcWithTrackProgressView - (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.trackColor = [UIColor cyanColor];
self.progressColor = [UIColor cyanColor];
}
return self;
} - (void)drawRect:(CGRect)rect
{
//绘制圈
UIBezierPath *trackPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(rect, , )];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 0.5);
CGContextAddPath(context, trackPath.CGPath); [self.trackColor setStroke];
CGContextDrawPath(context, kCGPathStroke);//绘制进度
[self.progressColor setFill];
CGFloat startAngle = - M_PI_2;
CGFloat endAngle = self.progress * * M_PI + startAngle;
CGPoint center = CGPointMake(CGRectGetWidth(rect) / , CGRectGetHeight(rect) / );
CGFloat radius = CGRectGetHeight(rect) / - ;//设置半径
UIBezierPath *progressPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; CGContextAddPath(context, progressPath.CGPath);
CGContextAddLineToPoint(context, center.x, center.y);
CGContextDrawPath(context, kCGPathFill);
} - (void)setProgress:(CGFloat)progress
{
NSLog(@"%g", progress);
if (progress > ) {
progress = ;
}else if (progress < ){
progress = ;
}
_progress = progress;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsDisplay];
});
} @end
三、绘制一个圆环进度
效果图如下:
此效果分为两步实现,一部分是绘制圆环,一部分是绘制勾。我在这里使用的CoreGraphics来绘制环,勾的话是利用CAShapeLayer来实现的。代码如下:
@implementation AnnularProgressView - (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonSetup];
}
return self;
} - (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self commonSetup];
}
return self;
} - (void)commonSetup
{
self.arcColor = [UIColor cyanColor];
self.lineWidth = .f; //设置shapeLayer
CAShapeLayer *tick = [[CAShapeLayer alloc] init];
tick.bounds = self.bounds;
tick.position = CGPointMake(CGRectGetWidth(self.bounds) / , CGRectGetHeight(self.bounds) / );
CGFloat width = CGRectGetWidth(self.bounds);
CGFloat height = CGRectGetHeight(self.bounds);
UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
[bezierPath moveToPoint:CGPointMake(width * 0.25, height * 0.46)];
[bezierPath addLineToPoint:CGPointMake(width * 0.45, height * 0.71)];
[bezierPath addLineToPoint:CGPointMake(width * 0.78, height * 0.29)];
tick.path = bezierPath.CGPath;
tick.fillColor = [UIColor clearColor].CGColor;
tick.strokeColor = [UIColor cyanColor].CGColor;
tick.strokeStart = ;
tick.strokeEnd = ;
tick.lineWidth = self.lineWidth;
tick.lineCap = kCALineJoinRound; [self.layer addSublayer:tick]; self.tick = tick;
} - (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth); [self.arcColor setStroke]; //绘制圆环
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = self.progress * M_PI * + startAngle;
CGPoint center = CGPointMake(rect.size.width / , rect.size.height / );
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:rect.size.width / - self.lineWidth startAngle:startAngle endAngle:endAngle clockwise:YES];
CGContextAddPath(context, path.CGPath);
CGContextDrawPath(context, kCGPathStroke); self.tick.strokeEnd = self.progress;//设置勾的进度 } - (void)setProgress:(CGFloat)progress
{
NSLog(@"%g", progress);
if (progress > ) {
progress = ;
}else if (progress < ){
progress = ;
}
_progress = progress;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsDisplay];
});
}
四、注水动画
效果:
注水动画的实现主要是通过正余弦函数绘制来实现的。正余弦曲线公式如下:
正弦函数
y=Asin(ωx+φ)+k //正弦函数
y=Acos(ωx+φ)+k //余弦函数
其中
@interface WaveProgressView () @property (nonatomic, assign) CGFloat initialPhase;//初相
@property (nonatomic, strong) CADisplayLink *timer; @end //y=Asin(ωx+φ)+k
@implementation WaveProgressView - (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self commonSetup];
}
return self;
} - (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonSetup];
}
return self;
} - (void)commonSetup
{
CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(moveWave:)];
[timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; self.backgroundColor = [UIColor clearColor];
} - (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext(); UIBezierPath *sinPath = [UIBezierPath bezierPath];
UIBezierPath *cosPath = [UIBezierPath bezierPath];
CGFloat y;
CGFloat amplitude = ;//振幅
CGFloat palstance = M_PI / self.bounds.size.width;//角速度 CGPoint startPoint = CGPointMake(, CGRectGetHeight(rect));
[sinPath moveToPoint:startPoint];
[cosPath moveToPoint:startPoint];
//正弦曲线
for (CGFloat x = 0.0 ; x <= rect.size.width; x++) {
y = amplitude * sin(palstance * x + self.initialPhase);
CGPoint point = CGPointMake(x, y + CGRectGetHeight(rect) * ( - self.progress) - amplitude); [sinPath addLineToPoint:point];
} //余弦曲线
for (int x = ; x <= rect.size.width; x++) {
y = amplitude * cos(palstance * x + self.initialPhase);
CGPoint point = CGPointMake(x, y + CGRectGetHeight(rect) * ( - self.progress) - amplitude); [cosPath addLineToPoint:point];
} CGPoint endPoint = CGPointMake(CGRectGetWidth(rect), CGRectGetHeight(rect));
[sinPath addLineToPoint:endPoint];
[cosPath addLineToPoint:endPoint];
[[UIColor lightGrayColor] setFill]; CGContextAddPath(context, sinPath.CGPath);
CGContextDrawPath(context, kCGPathFill); [[UIColor cyanColor] setFill];
CGContextAddPath(context, cosPath.CGPath);
CGContextDrawPath(context, kCGPathFill);
} - (void)moveWave:(CADisplayLink *)timer
{
self.initialPhase += 0.1; dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsDisplay];
}); } - (void)setProgress:(CGFloat)progress
{
NSLog(@"%g", progress);
if (progress > ) {
progress = ;
}else if (progress < ){
progress = ;
}
_progress = progress;
} - (void)dealloc
{
[self.timer invalidate];
}
实现原理:设定好曲线的振幅、角速度,然后根据progress来设置正余弦曲线的绘制路径。利用CADisplayLink来不断的改变曲线的初相来达到曲线移动的效果。
你可以从这里下载demo
iOS 动画篇 (三) CADisplayLink与CoreGraphics实现动画的更多相关文章
- 自己定义控件三部曲之动画篇(十三)——实现ListView Item进入动画
前言:宝剑锋从磨砺出,梅花香自苦寒来 相关文章: <Android自己定义控件三部曲文章索引>: http://blog.csdn.net/harvic880925/article/det ...
- iOS开发UI篇—iOS开发中三种简单的动画设置
iOS开发UI篇—iOS开发中三种简单的动画设置 [在ios开发中,动画是廉价的] 一.首尾式动画 代码示例: // beginAnimations表示此后的代码要“参与到”动画中 [UIView b ...
- iOS 动画篇 (二) CAShapeLayer与CoreAnimation结合使用
接上一篇博客 iOS 动画篇(一) Core Animation CAShapeLayer是CALayer的一个子类,使用这个类能够很轻易实现曲线的动画. 先来一个折线动画效果: 示例代码: //1. ...
- iOS 开发之动画篇 - 从 UIView 动画说起
毋庸置疑的:在iOS开发中,制作动画效果是最让开发者享受的环节之一.一个设计严谨.精细的动画效果能给用户耳目一新的效果,吸引他们的眼光 —— 这对于app而言是非常重要的. 本文作为动画文集的第一篇, ...
- iOS开发--动画篇之layout动画深入
"不得不说,单单是文章的标题,可能不足以说明本文的内容.因此,在继续讲述约束动画之前,我先放上本文要实现的动画效果." 编辑:Bison投稿:Sindri的小巢 约束动画并不是非常 ...
- iOS动画篇:UIView动画
iOS的动画效果一直都很棒很,给人的感觉就是很炫酷很流畅,起到增强用户体验的作用.在APP开发中实现动画效果有很多种方式,对于简单的应用场景,我们可以使用UIKit提供的动画来实现. UIView动画 ...
- iOS开发——动画篇Swift篇&动画效果的实现
Swift - 动画效果的实现 在iOS中,实现动画有两种方法.一个是统一的animateWithDuration,另一个是组合出现的beginAnimations和commitAnimation ...
- iOS 动画篇 之 Core Animation (一)
iOS中实现动画有两种方式,一种是自己不断的通过drawRect:方法来绘制,另外一种就是使用核心动画(Core Animation). 导语: 核心动画提供高帧速率和流畅的动画,而不会增加CPU的负 ...
- iOS动画篇:核心动画
转:http://www.cocoachina.com/ios/20160517/16290.html 基本概念 1.什么是核心动画 Core Animation(核心动画)是一组功能强大.效果华丽的 ...
随机推荐
- Eclipse 插件安装、升级和卸载的方法
Eclipse 的插件可以装在内部,也可以装在外部,装在内部的方法很简单:把插件的features和plugins目录copy到eclipse的安装目录即可. eclipse和其插件升级比较频繁,用过 ...
- 让你高效的理解JavaScript中的同步、异步和事件循环
"同步请求","异步请求"相信这两词在程序猿的世界中频频出现,到底是词性的妖娆,还是撸代码的基础要求,下面直接分享本人学习的好东西,保证让你深入浅出,爽得不要不 ...
- .net 裁剪图片(不压缩)
命名空间: using System.Drawing; using System.Drawing.Imaging; /// <summary> /// 生成图片缩略文件 /// </ ...
- mybatis框架(5)---动态sql
那么,问题来了: 什么是动态SQL? 动态SQL有什么作用? 传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误.Mybatis的动态S ...
- 二叉树Bynary_Tree(2):二叉树的递归遍历
7/18/2017 正在码,理解完就写博 7/21/2017 终于码完,借助链表实现的队列撸一个二叉树对于我来说有难度,撸了两天没有成果,我最后选用的是数组实现的循环队列去撸一个二叉树 正文如下: 以 ...
- (精选)Xcode极速代码,征服Xcode,xcode插件
插件 1 http://blog.csdn.net/qq_30513483/article/details/52349997 插件2 http://www.code4app.com/forum.ph ...
- jsp上的九个隐含对象
首先说一说件jsp的原理.jsp被认为最经典的解释是 “嵌入了java 代码的html”. 在网上查了一些资料,和我本身对jsp的认识,总结如下: jsp本质上是一个servlet,继承自 当第一次 ...
- echarts中如何使用timeline组件
1.吃碗面 这里关于echarts3 官网的示例我不得不吐槽一下,逼格真高!一小部分示例动不动数据就是国家统计局搞出来的,你脸真大.当然他们做的示例的确是很好,这一点毫无疑问.当我看了echarts3 ...
- 平方根的C语言实现(二) —— 手算平方根的原理
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7220506.html 作者:窗户 Q ...
- ArcGIS 网络分析[8.3] 设置IDENetworkDataset的属性及INetworkDataset的对比/创建网络数据集
创建网络数据集就得有各种数据和参数,这篇文章很长,慎入. 网络分析依赖于网络数据集的质量,这句话就在这里得到了验证:复杂.精确定义. 本节目录如下: 1. INetworkDataset与IDENet ...