此框架把屏幕上的内容组合起来,这个内容被分解成图层,放到图层树中,这个树造成了你能在应用程序看到的内容的基础html
图层在iOS中就是CALayer
类
当咱们建立一个UIView
类的时候就会同时建立这个类的layer
属性。 而UIView
和CALayer
分工明确。ios
UIView
类确切的知道响应链,能够响应事件。
UIView
封装了CALayer的部分功能。好比UIView
中的frame
、center
属性对应CALayer
中的frame
、position
。
UIView
还封装了高级API使动画更简单。
UIView
还具备自动排版、布局的功能git
CALayer
是UIView
的内部实现细节,真正负责屏幕上的显示和动画。
CALayer
的部分属性并无被UIView
暴露。好比:
~ 阴影、圆角、带颜色的边框
~ 3D变换(后面会讲到UIView
只能够作仿射变换)
~ 透明遮罩算法
最好使用使用视图而不是单独的图层的缘由之一有:视图能够进行自动布局,自适应屏幕的翻转。而图层是作不到这样的框架
对于什么时候使用CALayer
。能够参考以下条件:ide
UIView
提供的动画方案不能知足你的要求函数
须要使用 UIView
没有暴露的CALayer
的属性布局
使用CALayer的特定子类,提升应用性能(后面会讲到CAShaperLayer
、CATiledLayer
等等)性能
Core Animation
以前须要先讲讲一些基础知识anchorPoint
。是相对值,而不是绝对值。即便大小改变,也不用调整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决定)改变的时候就可拉伸。
布局
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
。若是父图层发生移动,子图层也会跟着移动bounds
来实现内容滚动的效果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;
//接受一个在本图层坐标系下的点,若是这个点在图层范围内就返回YES - (BOOL)containsPoint:(CGPoint)p;
//返回能接收这个点的最远CALayer子代。若是这个点在最外面图层的范围以外,则返回nil //若是设置了zPosition,返回的就不必定是最前方的Layer - (CALayer *)hitTest:(CGPoint)p;
× 圆角cornerRadius
maskToBounds
会依此属性截取× 图层边框borderColor
、borderWidth
bounds
绘制,在全部子图层以前bounds
变化,而不是图层内容× 阴影shadowOffset
、shadowColor
shadowOffset
是CGSize
类型的值。宽度控制横向的移动,高度控制纵向的移动
shadowRadius
属性控制着阴影的模糊度,数值越大越模糊和天然
shadowPath
是CGPathRef
类型。单独于图层形状以外指定阴影的形状
与直接指定
shadowPath
相比,图层的阴影根据图层内容动态计算阴影的形状。比较消耗性能
由于图层的阴影老是在图层范围外,因此直接使用
maskToBounds
的时候会把阴影给裁剪掉。
1、能够添加一个专门显示阴影的图层来获得maskToBounds
+shadow
的效果
2、指定shadowPath
× 图层蒙版mask
属性 —— 是一个CALayer类型,定义了父图层的部分可见区域。
mask
图层最重要的是它的轮廓,赋值了mask属性,就会按照mask图层的形状把父视图进行切割,保留mask
图层内的父视图内容,舍弃图层外的父视图内容
× 拉伸过滤Filter
—— 当图片须要显示不一样大小的时候,拉伸过滤的算法就起到做用了。CALayer有三种过滤算法
kCAFilterTrilinear
默认的过滤算法为linear,trilinear比 linear可以更好的支持大图;对于比较小的图或者是差别特别明显,极少斜线的大图,使用Neareset能够呈现更好的效果。
× 组透明GroupOpacity
——整个图层树有一个总体的透明效果仍是进行透明度的混合叠加
× 光栅化shouldRasterize
—— YES表明图层及其子图层会被整合成一个总体的图片
使用了shouldRasterize
,就要同步设置rasterizationScale
来匹配屏幕
layer.rasterizationScale = [UIScreen mainScreen].scale;
→ 仿射变换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的子类能够解决这个问题
→ 固体对象