iOS核心动画(基础篇)
Core Animation相关内容基本介绍
此框架把屏幕上的内容组合起来,这个内容被分解成图层,放到图层树中,这个树形成了你能在应用程序看到的内容的基础
图层在iOS中就是CALayer
类
当我们创建一个UIView
类的时候就会同时创建这个类的layer
属性。 而UIView
和CALayer
分工明确。
UIView
类继承自UIResponder,确切的知道响应链,可以响应事件。
UIView
封装了CALayer的部分功能。比如UIView
中的frame
、center
属性对应CALayer
中的frame
、position
。
UIView
还封装了高级API使动画更简单。
UIView
还具有自动排版、布局的功能
CALayer
是UIView
的内部实现细节,真正负责屏幕上的显示和动画。
CALayer
的部分属性并没有被UIView
暴露。比如:
~ 阴影、圆角、带颜色的边框
~ 3D变换(后面会讲到UIView
只可以做仿射变换)
~ 透明遮罩
最好使用使用视图而不是单独的图层的原因之一有:视图可以进行自动布局,自适应屏幕的翻转。而图层是做不到这样的
对于何时使用CALayer
。可以参考如下条件:
UIView
提供的动画方案不能满足你的要求需要使用
UIView
没有暴露的CALayer
的属性使用CALayer的特定子类,提高应用性能(后面会讲到
CAShaperLayer
、CATiledLayer
等等)
在讲解Core Animation
之前需要先讲讲一些基础知识
1. iOS中使用的坐标系统:
- 点 —— @1、@2、@3分别代表每个点1个、2个、3个像素。是为了在retain设备和普通设备上有同样的显示效果
- 像素 —— UIImage可以指定点度量大小,是一种分辨率解决方案。而CGImage则会使用像素
- 单位 —— 类似于{0,0,1,1}。比如
anchorPoint
。是相对值,而不是绝对值。即使大小改变,也不用调整
2. CALayer设置contents
属性
※ contentsGravity
※ contentsScale
※ contentsRect
※ contentsCenter
在开发中苹果建议在UIView中不要实现一个空的drawRect:方法。这是因为实现这个方法的View会生成一个寄宿图。这个寄宿图就是CALayer的contents属性。
contentsGravity
是控制内容在边界内如何对齐。对应UIView中的contentMode属性。可选的类型就是top、left、right、center、aspect、fill 等等。contentsScale
就是表明寄宿图图片的精度大小。1.0就是每个点绘制一个像素。2.0就是每个点绘制两个像素。就是retain屏幕。
tip:contentsGravity设置的选项是没有拉伸图片的话,这个属性的设置才会有显而易见的效果。
contentsRect
使用的是单位坐标。指定一个矩形,范围外的图片会被裁剪。然后用矩形内的内容进行填充contentsCenter
使用的是单位坐标。定义了一个固定的边框和一个在图层上可拉伸的区域。
例如:设置为{0.25,0.25,0.5,0.5},那么图层的四个边角的内容不变,而其他区域内容在图层大小(由contentsGravity决定)改变的时候就可拉伸。
3. 图层几何学
布局
frame
代表了图层的外部坐标(在父图层上占用的空间),bounds
是内部坐标,center和position代表了本图层的anchorPoint
在父图层的位置
锚点
anchorPoint
使用的是单位坐标,默认值为{0.5,0.5}.初始化
frame
为{0,0,100,100},则position
初始化为{0,0,50,50},如果改变anchorPoint
的值为{0,0},则图层左上角为锚点,左上角的点就在position
的位置frame
的值和bounds
、position
和transform
密切相关。改变其中一个值同时会改变其他的值。当图层进行transform旋转之后,frame代表的区域是整个轴对齐的区域
坐标系
- 一个图层的
position
依赖于它的父图层的bounds
。如果父图层发生移动,子图层也会跟着移动
- scrollView就是通过改变view的
bounds
来实现内容滚动的效果
- 和UIView严格的二维坐标不同的是,CALayer存在于一个三维空间中。除了x轴和y轴,还有一个z轴的存在。有两个属性可以描述在z轴的位置
zPosition
和anchorPointZ
通过增加图层的
zPosition
,就可以把图层前置,到达小于它的zPosition
值的图层的前面。zPosition
只能改变显示顺序,不能改变响应顺序。响应顺序还是按照addSubLayer
的顺序
可能会用到的API
- 坐标系的转换:
把一个图层坐标系下的点或矩形装换成另一个图层或坐标系的点
- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
- CALayer判断点的位置
//接受一个在本图层坐标系下的点,如果这个点在图层范围内就返回YES
- (BOOL)containsPoint:(CGPoint)p;
//返回能接收这个点的最远CALayer子代。如果这个点在最外面图层的范围之外,则返回nil
//如果设置了zPosition,返回的就不一定是最前方的Layer
- (CALayer *)hitTest:(CGPoint)p;
4. 视觉效果属性
× 圆角cornerRadius
- 只影响图层背景色
maskToBounds
会依此属性截取- 统一控制所有的角
× 图层边框borderColor
、borderWidth
- 沿着图层
bounds
绘制,在所有子图层之前 - 跟随图层的
bounds
变化,而不是图层内容
× 阴影shadowOffset
、shadowColor
shadowOffset
是CGSize
类型的值。宽度控制横向的移动,高度控制纵向的移动shadowRadius
属性控制着阴影的模糊度,数值越大越模糊和自然shadowPath
是CGPathRef
类型。单独于图层形状之外指定阴影的形状
与直接指定
shadowPath
相比,图层的阴影根据图层内容动态计算阴影的形状。比较消耗性能
因为图层的阴影总是在图层范围外,所以直接使用
maskToBounds
的时候会把阴影给裁剪掉。
一、可以添加一个专门显示阴影的图层来得到maskToBounds
+shadow
的效果
二、指定shadowPath
× 图层蒙版mask
属性 —— 是一个CALayer类型,定义了父图层的部分可见区域。
mask
图层最重要的是它的轮廓,赋值了mask属性,就会按照mask图层的形状把父视图进行切割,保留mask
图层内的父视图内容,舍弃图层外的父视图内容
× 拉伸过滤Filter
—— 当图片需要显示不同大小的时候,拉伸过滤的算法就起到作用了。CALayer有三种过滤算法
- kCAFilterLinear
- kCAFilterNearest
- kCAFilterTrilinear
默认的过滤算法为linear,trilinear比 linear能够更好的支持大图;对于比较小的图或者是差异特别明显,极少斜线的大图,使用Neareset可以呈现更好的效果。
× 组透明GroupOpacity
——整个图层树有一个整体的透明效果还是进行透明度的混合叠加
- iOS7之后默认为YES
× 光栅化shouldRasterize
—— YES代表图层及其子图层会被整合成一个整体的图片
使用了
shouldRasterize
,就要同步设置rasterizationScale
来匹配屏幕layer.rasterizationScale = [UIScreen mainScreen].scale;
5. 变换
→ 仿射变换affineTransform
:
是`CGAffineTransform`类型。`Core Graphics`框架对象。提供如下函数创建:
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
使用如下函数,初始化生成一个什么都不做的变换,也就是创建一个
CGAffineTransform
类型的空值,矩阵论中称作单位矩阵
CGAffineTransformIdentity
混合两个已经存在的变换矩阵,使用如下方法,在两个变换的基础上创建一个新的变换:
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
UIView
可以通过transform
属性做变换,对应CALayer
的affineTransform
属性tip:旋转常量M_PI是一个弧度单位。弧度用数学常量pi的倍数表示。可以用以下公式进行弧度角度换算
#define DEGREES_TO_RADIANS(x) ((x)/180.0 *M_PI)
这里要注意的是:旋转的时候会寻找最短路径进行旋转。比如弧度大于pi,就会逆时针旋转
混合变换 —— 使用以下函数可以在一个变换的基础上做更深层次的变换
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
注意:变换的顺序很重要,先旋转再平移和先平移再旋转的结果是不同的
→ 3D变换transform3D
CALayer的
transform
属性是CATransform3D
类型,是一个4x4的矩阵,声明如下struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
提供的创建函数
看起来和affineTransform类似,但是平移和缩放多了一个 z 参数,旋转除了弧度参数,还多了x、y、z 三个参数,分别代表每个方向轴的旋转
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)
z轴和x轴、y轴分别垂直,指向手机用户为正方向.绕z轴的旋转就等同于二维的仿射旋转,绕x轴和y轴的旋转就突破了二维的空间。
scale中的参数如果为负数先按轴翻转再进行缩放
接下来就说说怎么在应用显示拟真的3D效果透视投影
为了修正视图的远近不同的缩放比例,我们引入
投影变换
。通过修改矩阵中的m34
元素控制m34
的默认值是0,我们可以通过设置m34
为-1.0 /d
来应用透视效果,d
代表了想象中视角相机和屏幕之间的距离,以像素为单位。不需要计算,只需要估算一个就好了。通常500-1000就很好了。减少距离的值会增强透视效果,而一个非常大的值会让它基本失去透视效果
当视图远离观察者的时候物体会变小变远,当远离到一定距离的时候,就缩成了一个点,于是视角内的所有物体都汇聚消失在了同一个点。
接下来就说说关于这个点的事
灭点
在现实中,这个点通常是物体的中点,为了在应用中创建拟真效果 ,这个点应该是屏幕中点,或者至少是所有3D对象的中心点
CAAnimation
定义了这个点在变换图层的anchorPoint
(通常位于图层中心,但也有例外),当图层发生变换的时候,这个点永远是变换之前的anchorPoint
位置改变
position
就改变了图层的anchorPoint
,所以为了让所有3D视图共用一个灭点,可以先把视图放在屏幕中央,然后通过变换移动到指定位置幸运的是,苹果已经帮助我们把上面这个比较繁琐的事情封装了
sublayerTransform
属性是一个
CATransform3D
类型。它影响到全部子图层。如此我们可以统一设置子图层的透视变换和共享灭点。其他关于3D的属性
当把视图绕着Y轴旋转180度,我们就可以看到视图的背面。绘制的就是视图的镜像。可以通过
doubleSided
设置是否绘制视图背面。扁平化图层:
[ ] 1.绕Z轴旋转的两个图层做相反的旋转操作,第二个图层做的旋转会被第一个图层旋转抵消。
[ ] 2.而绕X轴和Y轴旋转的不同图层做相反的旋转操作并不会相互抵消。
原因是尽管
Core Animation
图层存在于3D空间之内,但它们并不都存在同一个3D空间。每个图层的3D场景其实是扁平化的,当你从正面观察一个图层,看到的实际上由子图层创建的想象出来的3D场景至少当你用正常的CALayer的时候是这样,CALayer有一个叫做CATransformLayer的子类可以解决这个问题
→ 固体对象
- 在应用中创建一个正方体,具体代码
iOS核心动画(基础篇)的更多相关文章
- ios核心动画(基础动画)
一.简单介绍 CAPropertyAnimation的子类 属性解析: fromValue:keyPath相应属性的初始值 toValue:keyPath相应属性的结束值 随着动画的进行,在长度为du ...
- iOS核心动画(专用图层篇)
之前的文章我们了解了Core Animation中图层的一些基础知识.没有看过的传送门在此: iOS核心动画基础篇 那么在了解了这些基础知识之后,接下来进入专用图层的了解 苹果为了方便和性能,封装了几 ...
- iOS开发UI篇—核心动画(基础动画)
转自:http://www.cnblogs.com/wendingding/p/3801157.html 文顶顶 最怕你一生碌碌无为 还安慰自己平凡可贵 iOS开发UI篇—核心动画(基础动画) iOS ...
- IOS 动画专题 --iOS核心动画
iOS开发系列--让你的应用“动”起来 --iOS核心动画 概览 通过核心动画创建基础动画.关键帧动画.动画组.转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等.在今天的文章里您可以看 ...
- iOS核心动画学习整理
最近利用业余时间终于把iOS核心动画高级技巧(https://zsisme.gitbooks.io/ios-/content/chapter1/the-layer-tree.html)看完,对应其中一 ...
- iOS 核心动画 Core Animation浅谈
代码地址如下:http://www.demodashi.com/demo/11603.html 前记 关于实现一个iOS动画,如果简单的,我们可以直接调用UIView的代码块来实现,虽然使用UIVie ...
- IOS 核心动画之CAKeyframeAnimation - iBaby
- IOS 核心动画之CAKeyframeAnimation - 简单介绍 是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation ...
- iOS核心动画高级技巧之核心动画(三)
iOS核心动画高级技巧之CALayer(一) iOS核心动画高级技巧之图层变换和专用图层(二)iOS核心动画高级技巧之核心动画(三)iOS核心动画高级技巧之性能(四)iOS核心动画高级技巧之动画总结( ...
- iOS核心动画高级技巧之图层变换和专用图层(二)
iOS核心动画高级技巧之CALayer(一) iOS核心动画高级技巧之图层变换和专用图层(二)iOS核心动画高级技巧之核心动画(三)iOS核心动画高级技巧之性能(四)iOS核心动画高级技巧之动画总结( ...
随机推荐
- 【loj2983】【WC2019】数树
题目 两颗\(n\)个点的树T1和T2,有\(y\)种颜色; 现在给每个点染色,要求公共边端点的颜色相同,求: 1.op=0 , T1和T2都确定,求合法染色方案数: 2.op=1 , T1确 ...
- Mac查看进程
Last login: Tue Jun 11 11:18:10 on ttys001 liangyufengdeMacBook-Pro:vod-admin liangyufeng$ lsof -i:6 ...
- 设置多个className
有时候我们需要有选择地设置多个className function myComponent(props) { const myClassName = { 'aaa', {'bbb': props.ne ...
- mysql 根据发音查找内容
当前表 mysql> select * from table1; +----------+------------+-----+ | name_new | transactor | pid | ...
- RocketMq重复消费问题排查
前情 出现了重复消费的问题,同一个消息被重复消费了多次,导致了用户端收到了多条重复的消息,最终排查发现,是因为消费者在处理消息的方法onMessage中有异常没有捕获到,导致异常上抛,被consume ...
- TCP Keepalive笔记
TCP是无感知的虚拟连接,中间断开两端不会立刻得到通知.一般在使用长连接的环境下,需要心跳保活机制可以勉强感知其存活.业务层面有心跳机制,TCP协议也提供了心跳保活机制. 长连接的环境下,人们一般使用 ...
- Git提交(PUSH)时记住密码 - 不用每次都输入密码
开发使用的团队搭建好的GitLab服务器来作为项目共享开发,由于我不是最高权限,没办法把我git生成的SSH-Key放到服务器里面去,所有只好在每次提交的时候配置git config来记录密码不过期来 ...
- Nim游戏博弈(收集完全版)
Nim游戏证明参见: 刘汝佳训练指南P135-写的很酷! 知乎上SimonS关于Nim博弈的回答! Nim游戏的概述: 还记得这个游戏吗? 给出n列珍珠,两人轮流取珍珠,每次在某一列中取至少1颗珍珠, ...
- jmeter 参数化大数据取唯一值方式
jmeter 参数化大数据取唯一值方式 一.用时间函数: 因为时间戳永远没有重复,jmeter参数化,而且要取唯一值,可以考虑用时间函数加上其他函数一起: # 以13位的时间戳作为 userID no ...
- 清理收藏夹中的CSS
1.去掉元素的属性, 例如宽度 #blog-calendar { width: initial !important; }