二、CoreAnimation之寄宿图详解
在之前的图层树中我们知道,可以使用CALayer对象创建一些有背景颜色的图层,其实使用CALayer,不仅可以利用其展示背景颜色,还可以展示图片。而这些展示内容,其实就是CALayer的寄宿图。这一节我们将来探索下CALayer寄宿图。
在CALayer中有一个属性叫做contents,这个属性的类型为id,意味着它可以是任何类型的对象,也就意味这即使你给contents属性赋任意对象值,您的项目都可以编译通过。然而,编译通过不代表使用正确,如果您给contents赋的不是CGImage对象,您的图层将展示一片空白。那既然如此,为何还要声明为id类型而不是CGImage类型呢?原因是Mac OS的历史原因造成的。在Mac OS系统中,CALayer的contents属性可以是CGImage和NSImage对象,因此CALayer的contents属性为id类型。
事实上,您真正需要给contents属性赋值的类型应该是CGImageRef,这是一个指向CGImage结构的指针。UIImage有一个CGImage属性,它返回一个CGImageRef指针。如果您想把这个值直接赋值给CALayer的contents属性,那您将得到一个编译错误。因为CGImageRef并不是一个真正的Cocoa对象,而是一个Core Foundation类型。
尽管Core Foundation类型跟Cocoa对象在运行时貌似很像,但他们并不是类型兼容的,不过我们仍然可以通过桥接的方式(ARC环境下),即bridge关键字转换。如果要给图层的寄宿图赋值,可以使用以下转换方法:
UIImage *image = [UIImage imageNamed:@"img01.png"];
layer.contents = (__bridge id)image.CGImage;//注意是两个下划线
这个时候,您可能想起了UIImageView,也是用来承载UIImage对象的,那么CALayer有没有和UIImageView的相似点呢?
答案是有的,在UIImageView中,有一个contenMode属性,用于选择内容填充模式.相似的,在CALayer中,也存在这样一个属性,即contentGravity,它的枚举值如下
- kCAGravityCenter
- kCAGravityTop
- kCAGravityBottom
- kCAGravityLeft
- kCAGravityRight
- kCAGravityTopLeft
- kCAGravityTopRight
- kCAGravityBottomLeft
- kCAGravityBottomRight
- kCAGravityResize
- kCAGravityResizeAspect
- kCAGravityResizeAspectFill
和contentMode一样,contentGravity的目的是为了解决内容在图层中的边界的对齐模式。
layer.contentsGravity = KCAGravityResizeAspect;
contentsScale:该属性定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数。一般情况下,该属性的表现并不明显,它并不是总对屏幕上的寄宿图有影响,如果您尝试对我们的上面的layer设置不同的contentsScale值,您就会发现根本没有任何的视觉上变化。因为contents由于设置了contentsGravity属性,所以他已经被拉伸以适应图层的边界。如果您只是单纯的想要放大contents的图片,您可以通过使用图层的transform和affineTransform属性来达到这个目的,因为这种放大,并非contentsScale的作用所在。
contentsScale属性其实属于支持高分辨率(Retina)屏幕机制的一部分,它用来判断在绘制图层的时候应该为寄宿图创建的空间打下,和需要显示的图片拉伸度(假设没有设置contentsGravity属性)。UIView有一个类似功能但是非常少用到的contentScaleFactor属性。
如果contentsScale设置为1.0,将会以每个点1像素绘制图片,如果设置为2.0,则会以每个点2像素绘制图片,这就是我们知道的Retina屏幕。这并不会对我们在使用contentsGravity时产生任何影响,因为该属性仅仅是拉伸图片适应图层而已,根本不会考虑到分辨率问题,但是如果我们把contentsGravity设置为KCAGraviryCenter(这种模式不会拉伸图片),那将会有很明显的变化。
没有设置时代码如下:
CALayer *layer = [CALayer layer]; layer.frame = CGRectMake(, , , ); layer.contents = (__bridge id)[UIImage imageNamed:@"001.jpg"].CGImage; [self.view.layer addSublayer:layer];
效果图如下:
当加上下面一句时
layer.contentsGravity = kCAGravityCenter;
效果图如下
如您所见,我们的图片不仅变大而且有像素的颗粒感。这是因为和UIImage不同,CGImage没有拉伸的概念。当我们使用UIImage去读取图片时,它读取了高质量的Retina版本的图片,但是当我们用CGImage来设置图层内容时,拉伸这个属性在转换的时候就丢失了。因此我们需要手动设置contentScale来修复这个问题。
layer.contentsScale = [UIScreen mainScreen].scale;
效果图如下:
contentsRect:CALayer的contentsRect属性允许我们在图层边框里显示寄宿图的一个子域。这涉及到图片是图和显示和拉伸的,所以要比contentsGravity灵活多了。和bounds,frame不同,contentsRect不是按点来计算的,它使用了单位坐标(值在0~1之间),是一个相对值(像素和点是绝对值)。所以他们是相对于寄宿图的尺寸的 。iOS使用了以下的坐标系统:
- 点:在iOS和Mac os中最常见的坐标体系。点就像是虚拟的像素,也被称为逻辑像素。在标准设备上,一个点就是一个像素,但在Retina设备上,一个点就等于2*2个像素。iOS用点作为屏幕的坐标测算体系就是为了在Retina设备和普通设备上能有一致的视觉效果
- 像素:物理像素坐标并不会用来屏幕布局,但是仍然与图片有相对关系。UIImage是一个屏幕分辨率解决方案,所以指定点来度量大小。但是一些底层的图片表示如CGImage就会使用像素,所以您要清楚在Retina屏幕和普通设备上,他们表现出来了不同的大小
- 单位:对于与图片大小或是图层边界相关的显示,单位坐标是一个方便的度量方式,当大小改变的时候,也不需要再次调整。单位坐标在OpenGL这种纹理坐标系统中用得很多,CoreAnimation中也用到了单位坐标
默认的contentsRect是{0,0,1,1},这意味着整个寄宿图默认都是可见的。如果我们指定一个小一点的矩形,
layer.contentsRect = CGRectMake(, , 0.5, 0.5);
图片就会被裁剪,如图:
而contentsRect最有趣的用法在于,它可以进行图片拼合。图片可以在屏幕上独立的变换位置,载入拼合的图片。 具体做法是创建多个CALayer对象,每个对象都添加一个寄宿图,然后将这些layer添加在一个layer上即可。
自定义寄宿图:
给contents赋值CGImage并不是唯一设置寄宿图的方法,我们也可以直接利用Core Graphics直接绘制寄宿图。能够通过继承UIView并实现-drawRect方法来自定义绘制。
-drawRect方法没有默认的实现,因为对于UIView来说,寄宿图并不是必须的,它不在意那到底是单调的颜色背景还是图片实例。如果UIView检测到-drawRect方法被调用了,它就会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以contentsSale的值,这无疑加大了内存的消耗。因此,如果您不需要寄宿图,那就不要创建这个方法了,这会造成CPU和内存的浪费,这也是为什么Apple建议:如果没有自定义绘制的任务就不要在子类中写一个空的drawRect方法。
当视图在屏幕上出现的时候,-drawRect方法就会被调用,该方法利用Core Graphics去绘制一个寄宿图,然后内容就会被缓存起来知道它需要被更新(一般是开发者调用了setNeedsDisplay方法和系统检测调用)。虽然-drawRect方法是一个UIView的方法,事实上都是底层的CALayer安排了重绘工作并保存了因此产生的图片。
CALayer有一个可选的delegate属性。实现了CALayerDelegate协议。当CALayer需要一个内容特定的信息时,就会从协议中请求。CALayerDelegate是一个非正式协议。其实就是说没有CALayerDelegate@protocol可以让你在类里引用啦。你只需要调用你想调用的方法,CALayer就会帮你完成城下的。
当需要被重绘时,CALayer会请求它的代理给他一个寄宿图来显示。它通过调用下面这个方法做到的:
- (void)displayLayer:(CALayer *)layer;
趁着这个机会,如果代理想直接设置contents属性的话,他就可以这么做,不然没有别的方法可以调用了。如果代理不实现该方法,CALayer就会转而尝试调用下面这个方法:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)cox;
在调用这个方法之前,CALayer创建了一个合适尺寸的空寄宿图(尺寸由bounds和contentsScale决定)和一个Core Graphics创建的绘制上下文环境,并为绘制寄宿图做准备,它作为参数传入。而且,在开发中,我们可以让某个CALayer对象显示地调用了-display方法。不同于UIVIew,当图层显示在屏幕上时,CALayer不会自动重绘它的内容,而是把重绘的决定权交给了开发者。
寄宿图就了解到这里,未完待续。
二、CoreAnimation之寄宿图详解的更多相关文章
- SPI总线协议及SPI时序图详解
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚 ...
- SPI总线协议及SPI时序图详解【转】
转自:https://www.cnblogs.com/adylee/p/5399742.html SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接 ...
- UML类图详解_关联关系_一对多
对于一对多的示例,可以想象一个账户可以多次申购.在申购的时候没有固定上限,下限为0,那么就可以使用容器类(container class)来搞,最常见的就是vector了. 下面我们来看一个“一对多” ...
- UML类图详解_关联关系_多对一
首先先来明确一个概念,即多重性.什么是多重性呢?多重性是指两个对象之间的链接数目,表示法是“下限...上限”,最小数据为零(0),最大数目为没有设限(*),如果仅标示一个数目级上下限相同. 实际在UM ...
- Java程序员从笨鸟到菜鸟之(一百零二)sql注入攻击详解(三)sql注入解决办法
sql注入攻击详解(二)sql注入过程详解 sql注入攻击详解(一)sql注入原理详解 我们了解了sql注入原理和sql注入过程,今天我们就来了解一下sql注入的解决办法.怎么来解决和防范sql注入, ...
- (转)CAS (4) —— CAS浏览器SSO访问顺序图详解(CAS Web Flow Diagram by Example)
CAS (4) —— CAS浏览器SSO访问顺序图详解(CAS Web Flow Diagram by Example) tomcat版本: tomcat-8.0.29 jdk版本: jdk1.8.0 ...
- 十图详解tensorflow数据读取机制(附代码)转知乎
十图详解tensorflow数据读取机制(附代码) - 何之源的文章 - 知乎 https://zhuanlan.zhihu.com/p/27238630
- CAS (6) —— Nginx代理模式下浏览器访问CAS服务器网络顺序图详解
CAS (6) -- Nginx代理模式下浏览器访问CAS服务器网络顺序图详解 tomcat版本: tomcat-8.0.29 jdk版本: jdk1.8.0_65 nginx版本: nginx-1. ...
- CAS (4) —— CAS浏览器SSO访问顺序图详解(CAS Web Flow Diagram by Example)
CAS (4) -- CAS浏览器SSO访问顺序图详解(CAS Web Flow Diagram by Example) tomcat版本: tomcat-8.0.29 jdk版本: jdk1.8.0 ...
随机推荐
- 平行四边形导航,背景颜色渐变动画(不支持IE6/7/8)
body{ font-size: 14px; } ul ,li{ margin:0px; padding:0px; list-style: none; } .box{ width: 1000px; h ...
- C 语言学习 第二次作业总结
本次作业内容,主要有以下几点: 新建 coding 帐号,且使用 coding 上传本次作业的代码 Printf及条件判断语句的使用 作业总结 作业总结: 同学们开始渐入佳境,能够较为流畅的写出合理的 ...
- yii的验证码
验证码比较麻烦,在三部分各有体现 controller <?php namespace app\controllers\demo_code; use yii\web\Controller; cl ...
- iOS小知识点(非UI部分)
1. _cmd 表示当前方法的@SEL指针, - (void)putString{} 对于这个函数_cmd 等效于@selector(putString)
- 解决:WPS for Linux提示“系统缺失字体symbol、wingdings、wingdings 2、wingdings 3、webding”
WPS for Linux提示“系统缺失字体symbol.wingdings.wingdings 2.wingdings 3.webding” 出现提示的原因是因为WPS for Linux没有自带以 ...
- 【BZOJ-3039&1057】玉蟾宫&棋盘制作 悬线法
3039: 玉蟾宫 Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 753 Solved: 444[Submit][Status][Discuss] D ...
- <<< java异常The import java.util cannot be resolved
异常:The import java.util cannot be resolved 原因:这是由于你的项目buildpath不对 解决方案:右键项目-------buildpath--------最 ...
- 借One-Class-SVM回顾SMO在SVM中的数学推导--记录毕业论文5
上篇记录了一些决策树算法,这篇是借OC-SVM填回SMO在SVM中的数学推导这个坑. 参考文献: http://research.microsoft.com/pubs/69644/tr-98-14.p ...
- DEDECMS标签调用汇总啊
非常有用的标签调用的方法 关键描述调用标签: <meta name="keywords" content="{dede:field name='keywords'/ ...
- JavaScript 数组中的 indexOf 方法
let arr = ['orange', '2016', '2016']; arr.indexOf('orange'); //0 arr.indexOf('o'); //-1 arr.indexOf( ...