动画黄金搭档:CADisplayLink&CAShapeLayer
我们在开发中有时会遇到一些看似非常复杂的动画,不知该如何下手,今天的这篇文章中我会讲到如何利用CADisplayLink
和CAShapeLayer
来构建一些复杂的动画,希望能在你下次构建动画中,给你一些启发。
在接下来的文章中,我们会构建如下的一个动画:
该动画是在du
的轮廓中进行,类似一个镂空效果,轮廓的填充是用双波浪的形式,类似于水流慢慢注入容器的过程。
动画使用CADisplayLink
来进行刷新,保证了动画的流程性,利用CAShapeLayer
来构建波浪的轮廓,最后利用CALayer
的mask
属性来实现逐渐填充的过程。
背景知识介绍
在动画创建过程的讲解之前,先介绍一下会使用到的一些知识点:
- CADisplayLink
- UIBezierPath
- CAShapeLayer
- mask
如果你已经对这些概念有了充分的了解,可以略过背景知识介绍
这一节。
1、CADisplayLink
用绘制的方式构建的动画,必然需要不断的刷新绘制的内容来呈现流畅的动画,CADisplayLink
就像是一个定时器,每隔几毫秒刷新一次屏幕。能让我们以和屏幕刷新频率相同的频率去刷新我们绘制到屏幕上的内容。CADisplayLink
的使用方式如下:
1 |
|
当CADisplayLink
注册到runloop以后,屏幕刷新的时候就会调用绑定到它上面的target所拥有的selector方法。停止CADisplayLink
的运行非常的简单,只需要调用它的invalidate
方法。
NSTimer和CADisplayLink有什么不同?
iOS设备的屏幕每秒会刷新60次,正常情况下CADisplayLink
在屏幕每次刷新时都会调用,精确度非常高,并且CADisplayLink
的使用场合相对专一,适合做UI的不停重绘,比如动画的连续绘制。
NSTimer
的使用范围要广泛很多,可以做单次或者循环处理某个任务,精度相比CADisplayLink要低。
2、UIBezierPath
使用UIBezierPath
类可以创建基于矢量的路径,它是Core Graphics框架关于CGPathRef
类型数据的封装,利用它创建直线或者曲线来构建我们想要的形状,每一个直线段或者曲线段的结束位置就是下一个线段开始的地方。这些连接的直线或者曲线的集合成为subpath。一个UIBezierPath
对象的完整路径包括一个或者多个subpath。
创建一个完整的UIBezierPath对象的完整步骤如下:
- 创建一个Bezier Path对象。
- 使用方法moveToPoint:去设置初始线段的起点。
- 添加line或者curve去定义一个或者多个subpath。
- 修改UIBezierPath对象跟绘图相关的属性。
3、CAShapeLayer
CAShapeLayer
是一个通过矢量图形而不是bitmap来绘制的图层子类。CAShapeLayer
可以用来绘制所有通过CGPath来表示的形状,上面讲到了可以用UIBezierPath
来创建任何你想要的路径,使用CAShapeLayer
的属性path
配合UIBezierPath
创建的路径,就可以呈现出我们想要的形状。
这个形状不一定要闭合,图层路径也不一定是连续不断的,你可以在CAShapeLayer
的图层上绘制好几个不同的形状,但是你只有一次机会去设置它的path、lineWith、lineCap
等属性,如果你想同时设置几个不同颜色的多个形状,你就需要为每个形状准备一个图层。
下面的示例代码是通过UIBezierPath
和CAShapeLayer
来创建一个简单的火柴人。
1 |
|
显示的形状如下:
4、mask
CALayer
有一个属性叫做mask
,通常被称为蒙版图层,这个属性本身也是CALayer类型,有和其他图层一样的绘制和布局属性。它类似于一个子视图,相对于父图层(即拥有该属性的图层)布局,但是它却不是一个普通的子视图。不同于一般的subLayer,mask
定义了父图层的可见区域,简单点说就是最终父视图显示的形态是父视图自身和它的属性mask
的交集部分。
mask
图层的color属性是无关紧要的,真正重要的是它的轮廓,mask
属性就像一个切割机,父视图被mask
切割,相交的部分会留下,其他的部分则被丢弃。
CALayer的蒙版图层真正厉害的地方在于蒙版图层不局限于静态图,任何有图层构成的都可以作为mask
属性,这意味着蒙版可以通过代码甚至是动画实时生成。这也为我们实现示例中波浪的变化提供了支持。
绘制波浪轮廓
我们利用UIBezierPath
来绘制波浪的轮廓,通过正弦函数和余弦函数来创建顶部的波浪曲线,在单位为1的右手直角坐标系中的曲线变化如下:
可以看到在(-2π , 2π )的范围类,y
值在[-1, 1]
之间变化。
以正弦曲线为例,它可以表示为y=Asin(ωx+φ)+k
,公式中各符号表示的含义:
- A–振幅,即波峰的高度。
- (ωx+φ)–相位,反应了变量y所处的位置。
- φ–初相,x=0时的相位,反映在坐标系上则为图像的左右移动。
- k–偏距,反映在坐标系上则为图像的上移或下移。
- ω–角速度,控制正弦周期(单位角度内震动的次数)。
通过上面的函数,我们就能计算出波浪曲线上任意位置的坐标点。通过UIBezierPath
的函数addLineToPoint
来把这些点连接起来,就构建了波浪形状的path。只要我们的设定相邻两点的间距够小,就能构建出平滑的正弦曲线,构建正弦波浪的代码如下:
1 |
|
显示的效果如下:
在这里我们设定了两个正弦曲线上的点的横坐标间距是1,现在来解释一下通过横坐标x来得出y的计算过程:
y = self.maxAmplitude * sinf(360.0 / _waveWidth * (x * M_PI / 180) * self.frequency + self.phase * M_PI/ 180) + self.maxAmplitude;
第一个self.maxAmplitude
表示曲线的波峰值,360.0 / _waveWidth
计算出单位间距1pixel代表的度数,x * M_PI / 180
表示将横坐标值转换为角度。self.frequency
表示角速度,即单位面积内波动次数,波浪的大小。self.phase * M_PI/ 180
代表上面公式中的初相,通过规律的变化初相,可以制造出曲线上的点动起来的效果,self.maxAmplitude
代表偏距,由于我们需要让波浪曲线的波峰在layer
的范围内显示,所以需要将整个曲线向下移动波峰大小的单位,因为CALayer
使用左手坐标系,所以向下移动需要加上波峰的大小。
让波浪曲线动起来
正弦或者余弦曲线上的点,不论角度如何,在y轴上的变化范围在它的波峰与波谷之间。拿单位正交直角坐标系来说,只要我们规律性的增加角度值,那么曲线上的点就会在[1, -1]之间变化,我们以曲线上x=0的点为例,角度的不断增加,会让它的y值规律性的来回变化:
如若曲线上的点都能这样规律的变化,我们就能让波浪曲线浪起来。
要让曲线上所有的点都动起来,在这里我们使用CADisplayLink
来不断刷新由UIBezierPath
创建的形状,两次刷新之间曲线的变化通过增加初相来实现,代码如下:
1 |
|
把CAShapeLayer
的背景色设置为淡红色,波浪曲线会在Layer
的bounds类波动,动起来的波浪曲线如下:
构建波浪上升的镂空效果
到目前为止,我们利用CAShapeLayer
、UIBezierPath
以及CADisplayLink
实现了动起来的波浪效果,下面我们需要实现的是在du
的轮廓里,水波不断上升填充的过程,整个动画过程中,会呈现一个du
的镂空效果,在它轮廓之外的水波则不会显示,这样的效果需要借助CALayer
的mask
属性来实现。
我们需要的动画素材如下:
将这三个图片位置设置为一样,底层放置动画中一直显示的底层轮廓,中间层用以实现余弦波浪,最外层用于实现正弦波浪,将中间层和最外层图片的mask
属性赋值为我们创建的用来呈现余弦波浪和正弦波浪的CAShapeLayer
,这样动画开始后,利用CADisplayLink
来不断刷新两个CAShapeLayer
的path来让波浪浪起来,再利用CABasicAnimation
来对两个CAShapeLayer
的position
进行动画,实现从下到上的填充效果。我们想要的效果就完成了:
完整的代码示例在这里
参考
动画黄金搭档:CADisplayLink&CAShapeLayer的更多相关文章
- 动画黄金搭档:CADisplayLink & CAShapeLayer
我们在开发中有时会遇到一些看似非常复杂的动画,不知该如何下手,今天的这篇文章中我会讲到如何利用CADisplayLink和CAShapeLayer来构建一些复杂的动画,希望能在你下次构建动画中,给你一 ...
- JavaScript大杂烩8 - 理解文本解析的"黄金搭档"
文本解析"黄金搭档" - String与RegExp对象 文本解析是任何语言中最常用的功能,JavaScript中也是一样,而正则表达式作为最常用的方式,JavaScript也同样 ...
- MarkDown的黄金搭档Typora编辑器
让你成为热爱写作的程序员 学习编程的小伙伴,要养成记笔记的好习惯,并发布到博客上去与同行分享你的学习经验,那么传统的文本编辑器或多或少会不尽人意,效率低,而且码字体验与写代码完全不一样. 下面推荐一款 ...
- Apache Hudi:CDC的黄金搭档
1. 介绍 Apache Hudi是一个开源的数据湖框架,旨在简化增量数据处理和数据管道开发.借助Hudi可以在Amazon S3.Aliyun OSS数据湖中进行记录级别管理插入/更新/删除.AWS ...
- iOS - Core Animation 核心动画
1.UIView 动画 具体讲解见 iOS - UIView 动画 2.UIImageView 动画 具体讲解见 iOS - UIImageView 动画 3.CADisplayLink 定时器 具体 ...
- iOS中的时钟动画
iOS 动画效果非常多,我们在开发中可能会遇到很多动画特效,我们就会用到核心动画框架CoreAnimation,核心动画里面的动画效果有很多,都是在QuartzCore.framework框架里面,今 ...
- Swift:使用CAShapeLayer打造一个ProgresssBar
ProgressBar是一个很小却在很多地方都会用到的东西.也许是网络连接,也许APP本身有很多东西需要加载的.默认的只有一个旋转的菊花,对于打造一款个性的APP这显然是不够的.这里就使用CAShap ...
- 深度掌握SVG路径path的贝塞尔曲线指令
一.数字.公式.函数.变量,哦,NO! 又又一次说起贝塞尔曲线(英语:Bézier curve,维基百科详尽中文释义戳这里),我最近在尝试实现复杂的矢量图形动画,发现对贝塞尔曲线的理解馒头那么厚,是完 ...
- 常用iOS第三方库以及XCode插件介绍
第三方库 CocoaPod CocoaPod并不是iOS上的第三方库 而是大名鼎鼎的第三方库的管理工具 在CocoaPod没有出现之前 第三方库的管理是非常痛苦的 尤其是一些大型的库(比如nimbus ...
随机推荐
- windows2008r2的时间同步小结
一.在windows2008r2域控的环境下进行时间同步的配置(当已经拥有可以使用的ntp服务器,并知晓ip,客户端到其网络正常): 客户端的配置过程如下: 1.搜索窗口输入 gpedit.msc 打 ...
- redis数据类型之—Set
(1)set 简单介绍 set集合的数据是不重复的.无序的,一个集合类型键可以存储至多2^32-1 个字符串. (2)set 常用命令
- 简单的后台json,前台解析 操作
后台: List<PageData> KeyWords=plantDefDetailCSAService.findKeyWords(pd); JSONArray array = new J ...
- 如何使用PL/SQL Developer查看和杀掉session
http://jingyan.baidu.com/article/3ea51489eb65b152e61bba8b.html
- 归一化交叉相关Normalization cross correlation (NCC)
归一化交叉相关Normalization cross correlation (NCC) 相关系数,图像匹配 NCC正如其名字,是用来描述两个目标的相关程度的,也就是说可以用来刻画目标间的相似性.一般 ...
- sqoop部署
下载安装包 sqoop-1.99.3-bin-hadoop200.tar.gz 解压 tar zxvf sqoop-1.99.3-bin-hadoop200.tar.gz 建立sqoop链接 ln - ...
- JavaScript必须了解的知识点总结【转】
整理的知识点不全面但是很实用. 主要分三块: (1)JS代码预解析原理(包括三个段落): (2)函数相关(包括 函数传参,带参数函数的调用方式,闭包): (3)面向对象(包括 对象创建.原型链,数据类 ...
- linux install StarDict
1. sudo apt-get install stardict 2. Downloads from: http://abloz.com/huzheng/stardict-dic/zh_CN/ 3. ...
- Asterisk manager API(AMI)文档(中文版)
Asterisk控制接口(AMI)允许管理客户端程序连接到一个asterisk实例并且可以通过TCP/IP流发送命令或读取事件.这在试图跟踪asterisk的状态或其中的电话客户端状态时很有用,AMI ...
- C#导入导出数据你该知道的方法。
导入数据 using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; us ...