本文主要介绍利用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 //余弦函数

其中

A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
(ωx+φ)——相位,反映变量y所处的状态。
φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
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实现动画的更多相关文章

  1. 自己定义控件三部曲之动画篇(十三)——实现ListView Item进入动画

    前言:宝剑锋从磨砺出,梅花香自苦寒来 相关文章: <Android自己定义控件三部曲文章索引>: http://blog.csdn.net/harvic880925/article/det ...

  2. iOS开发UI篇—iOS开发中三种简单的动画设置

    iOS开发UI篇—iOS开发中三种简单的动画设置 [在ios开发中,动画是廉价的] 一.首尾式动画 代码示例: // beginAnimations表示此后的代码要“参与到”动画中 [UIView b ...

  3. iOS 动画篇 (二) CAShapeLayer与CoreAnimation结合使用

    接上一篇博客 iOS 动画篇(一) Core Animation CAShapeLayer是CALayer的一个子类,使用这个类能够很轻易实现曲线的动画. 先来一个折线动画效果: 示例代码: //1. ...

  4. iOS 开发之动画篇 - 从 UIView 动画说起

    毋庸置疑的:在iOS开发中,制作动画效果是最让开发者享受的环节之一.一个设计严谨.精细的动画效果能给用户耳目一新的效果,吸引他们的眼光 —— 这对于app而言是非常重要的. 本文作为动画文集的第一篇, ...

  5. iOS开发--动画篇之layout动画深入

    "不得不说,单单是文章的标题,可能不足以说明本文的内容.因此,在继续讲述约束动画之前,我先放上本文要实现的动画效果." 编辑:Bison投稿:Sindri的小巢 约束动画并不是非常 ...

  6. iOS动画篇:UIView动画

    iOS的动画效果一直都很棒很,给人的感觉就是很炫酷很流畅,起到增强用户体验的作用.在APP开发中实现动画效果有很多种方式,对于简单的应用场景,我们可以使用UIKit提供的动画来实现. UIView动画 ...

  7. iOS开发——动画篇Swift篇&动画效果的实现

    Swift - 动画效果的实现   在iOS中,实现动画有两种方法.一个是统一的animateWithDuration,另一个是组合出现的beginAnimations和commitAnimation ...

  8. iOS 动画篇 之 Core Animation (一)

    iOS中实现动画有两种方式,一种是自己不断的通过drawRect:方法来绘制,另外一种就是使用核心动画(Core Animation). 导语: 核心动画提供高帧速率和流畅的动画,而不会增加CPU的负 ...

  9. iOS动画篇:核心动画

    转:http://www.cocoachina.com/ios/20160517/16290.html 基本概念 1.什么是核心动画 Core Animation(核心动画)是一组功能强大.效果华丽的 ...

随机推荐

  1. M03 利用Accord 进行机器学习的第一个小例子

    01 安装 Visual studio 2017. 不具备安装这个的话,也可安装,Microsoft Visual Studio Express (or equivalent) 02 创建 C# 的 ...

  2. (转)spring aop(下)

    昨天记录了Spring AOP学习的一部分(http://www.cnblogs.com/yanbincn/archive/2012/08/13/2635413.html),本来是想一口气梳理完的.但 ...

  3. 自学Zabbix3.5.1-监控项item-key详解

    自学Zabbix3.5.1-监控项item-key详解个人觉得艰难理解,故附上原文档:https://www.zabbix.com/documentation/3.0/manual/config/it ...

  4. java 对象的初始化过程

    PersonDemo p=new PersonDemo("lisi",20);这句话都做了什么事情? 因为new用到了PersonDemo.class,所以会先找到PersonDe ...

  5. 平方根的C语言实现(二) —— 手算平方根的原理

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7220506.html 作者:窗户 Q ...

  6. bzoj 3675: [Apio2014]序列分割

    Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...

  7. chmod 命令详解

    chmod 作用:修改目录或文件权限(= 赋值不管存在与否, + 增加权限)符号链接的权限无法变更, 如果用户对符号链接修改权限, 其改变会作用在被链接的原始文件. 参数: -R: 递归修改处理 -v ...

  8. 安装supervisord

    一:简介 supervisord是一个进程管理工具,提供web页面管理,能对进程进行自动重启等操作. 优点: - 可以将非后台运行程序后台运行 - 自动监控,重启进程 缺点: - 不能管理后台运行程序 ...

  9. 编译TensorFlow源码

      编译TensorFlow源码 参考: https://www.tensorflow.org/install/install_sources https://github.com/tensorflo ...

  10. (转) Linux中profile、bashrc、bash_profile之间的区别和联系

    原文地址:http://blog.csdn.net/chenchong08/article/details/7833242 /etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登 ...