本文主要介绍利用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. string.prototype.replace 和正则表达式

    字符串的replace方法是操作字符串的常用方法之一,但这个方法只有当与正则合并使用时,才能体现出它的强大之处. 语法:str.replace(regexp|substr, newsubStr|fun ...

  3. redis 报Operation against a key holding the wrong kind of value警告的解决方法

    WRONGTYPE Operation against a key holding the wrong kind of value github:https://github.com/antirez/ ...

  4. 通过 Sublime Package Control 安装插件后不能用的解决办法

    最近使用 Sublime 写 SASS 的时候需要使用高亮功能,通过 Package Control 安装了相关插件,但是安装之后没有反应,再次打开 Package Control 的时候,已经搜索不 ...

  5. ASP.NET Cookie 概述

    什么是 Cookie? Cookie 是一小段文本信息,伴随着用户请求和页面在 Web 服务器和浏览器之间传递.Cookie 包含每次用户访问站点时 Web 应用程序都可以读取的信息. 例如,如果在用 ...

  6. bzoj 4898: [Apio2017]商旅

    Description 在广阔的澳大利亚内陆地区长途跋涉后,你孤身一人带着一个背包来到了科巴.你被这个城市发达而美丽的市场所 深深吸引,决定定居于此,做一个商人.科巴有个集市,集市用从1到N的整数编号 ...

  7. lesson - 1 aming

    一.  Linux是什么* 关于Linux历史(http://www.aminglinux.com/bbs/thread-6568-1-1.html  需要大家查查资了解,也可以看看5期的视频)* 发 ...

  8. SpringMVC处理multipart请求.

    一.简述 multipart格式的数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域.在一般的表单输入域中,它所对应的部分中会放置文本型数据,但是如果上传文件的话,它所对应的部分可以是 ...

  9. 缓存(Cache)

    l如果每次进入页面的时候都查询数据库生成页面内容的话,如果访问量非常大,则网站性能会非常差.而如果只有第一次访问的时候才查询数据库生成页面内容,以后都直接输出内容,则能提高系统性能.这样无论有多少人访 ...

  10. Handwritten Parsers & Lexers in Go (Gopher Academy Blog)

    Handwritten Parsers & Lexers in Go (原文地址  https://blog.gopheracademy.com/advent-2014/parsers-lex ...