Core Animation (一) contents

一、contents

CALayer的contents属性,虽然被定义为id类型,貌似可以指向任何类型的对象,但是在实际中,如果给contents赋的不是CGImage,那么得到的layer显示的将是空白。

之所以定义为id,是为了兼容Mac OS,在Mac OS上,该属性对CGImage和NSImage都能生效。

二、contentsGravity

在使用UIImageView的时候,当我们加载的图片与imageView的大小比例不一致时,图片将会被拉伸。此时可以设置contentMode为UIViewContentModeScaleAspectFit。

同样的,在CALayer中,也有类似属性,即contentsGravity。该属性是个NSString,可选值为

kCAGravityCenter

kCAGravityTop

kCAGravityBottom

kCAGravityLeft

kCAGravityRight

kCAGravityTopLeft

kCAGravityTopRight

kCAGravityBottomLeft

kCAGravityBottomRight

kCAGravityResize

kCAGravityResizeAspect

kCAGravityResizeAspectFill

具体作用自测哈~~

三、contentsScale

contentsScale定义了content对应的图片的像素尺寸和视图大小的比例,默认为1。该属性属于支持高分辨率(Retina)屏幕机制的一部分。它用来判断在绘制图层的时候应该为寄宿图创建的空间大小,和需要显示

的图片的拉伸度(假设并没有设置 contentsGravity 属性)。UIView有一个类似功能但是非常少用到的 contentScaleFactor 属性。

如果contentsScale设置为1,将会以每个点1个像素绘制图片,如果设置为2,则会以每个点2个像素绘制图片,也就是我们常说的Retina屏幕。

此外,该属性与contentsGravity有时候会产生冲突,例如当我们设置contentsGravity为kCAGravityResizeAspect自动拉伸以适应图层后,设置contentsScale无效。

当我们用UIImage加载图片时,若图片为@2x图片,则UIImage的属性scale为2.因此一般设置contentsScale都是根据content(CGImage)对应的UIImage的scale来设置。

四、contentsRect

好啦,终点来了,其实这个才是真正想说的。

CALayer的contentsRect属性允许我们在contents中仅显示原图的一个子区域。

要注意,该属性虽然是一个CGRect类型,但其单位并非我们所熟知的点。它使用的是单位坐标,指定在0-1之间,是一个相对值(相对原图的宽高)。

附IOS用到的坐标系统简介:

点——在iOS和MacOS中最常见的坐标体系。点就像是虚拟的像素,也被称

作逻辑像素。在标准设备上,一个点就是一个像素,但是在Retina设备上,一

个点等于2*2个像素。iOS用点作为屏幕的坐标测算体系就是为了在Retina设备

和普通设备上能有一致的视觉效果。

像素——物理像素坐标并不会用来屏幕布局,但是仍然与图片有相对关系。

UIImage是一个屏幕分辨率解决方案,所以指定点来度量大小。但是一些底层

的图片表示如CGImage就会使用像素,所以你要清楚在Retina设备和普通设备

上,他们表现出来了不同的大小。

单位坐标——对于与图片大小或是图层边界相关的显示,单位坐标是一个方便的

度量方式,当大小改变的时候,也不需要再次调整。单位坐标在OpenGL这种

纹理坐标系统中用得很多,CoreAnimation中也用到了单位坐标。

默认的contentsRect是{0,0,1,1},也就是说整个原图默认可见,如果我们指定一个小一点的区域,那么layer上显示的将会是contents对应的原图中的一部分区域。比如设置为{0,0,0.5,0.5},如下图

显示的是右侧的样纸~~~

contentsRect最有意义的地方在于一种称为image sprites(图片拼合)的技术。这在游戏开发中应用特别广泛。

该技术典型的用法是,将一系列图片整合到一张大图上一次性载入,相比多次载入多张小图,这样做极大的能减少载入时间以及少许的内存使用和渲染性能。

现在网上有许多图片整合工具,如TexturePacker等等。(友情提醒:该工具整合图片时,有个trim属性,设置是否将png图片透明区域去除,最好关掉哈~保持原来的切图。更具体的用法不清楚的可以留言哈~~)

假设我们通过工具已经将多张图片整合到一起了,那么相应的会生成一个数据文件,用来记录图片名、图片在当前大图中的位置等信息。如下图

我们就可以根据该数据文件,从大图中解析出我们要的每个图片了。

经过测试后,使用拼合图,加载速度基本可以提升几倍。

我自测时弄了1700多张小图,整合成大图后5M多。

4s读取5M的拼合图仅需0.002-0.006秒,而依次读取1700多张小图耗时4-5秒。读取并将图片渲染到界面上,拼合图需0.1-0.2秒,而依次读取小图4-5秒以上。【顺带也可以发现,渲染和加载图片的耗时占比,渲染貌似小得多呢~~】

当然,当图片量不多就没有必要啦~~~

所以,这技术也就在游戏开发中吃得开,毕竟游戏各种动效大部分都靠图片~需要大量的图片才玩得动~~

最后附上显示的核心代码。在这里我将加载大图到内存后,然后相应的把每个小图显示的scrollView上。

//加载拼合图

- (CGFloat)loadSubLayers

{

CGFloat totalHeight = 0;

CGFloat maxWidth = 0;

NSDate *begin = [NSDate date];

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:self.data[@"meta"][@"image"] ofType:nil]];

CGFloat imageWidth = CGImageGetWidth(image.CGImage);

CGFloat imageHeight = CGImageGetHeight(image.CGImage);

for (NSString *item in [self.data[@"frames"] allKeys]) {

@autoreleasepool {

#ifdef NEEDDRAW

NSDictionary *frameDict = self.data[@"frames"][item];

CGFloat width = [frameDict[@"w"] floatValue];

CGFloat height = [frameDict[@"h"] floatValue];

CGRect contentRect = CGRectMake([frameDict[@"x"] floatValue] / imageWidth, [frameDict[@"y"] floatValue] / imageHeight, width / imageWidth, height / imageHeight);

CALayer *layer = [CALayer layer];

layer.contents = (__bridge id _Nullable)(image.CGImage);

layer.contentsGravity = kCAGravityResizeAspect;

layer.contentsRect = contentRect;

layer.frame = CGRectMake(0, totalHeight, width, height);

layer.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1].CGColor;

totalHeight += layer.bounds.size.height;

maxWidth = MAX(maxWidth, layer.frame.size.width);

[self.scrollView.layer addSublayer:layer];

#endif

}

}

NSDate *end = [NSDate date];

CGFloat timeStamp = [end timeIntervalSinceDate:begin];

self.scrollView.contentSize = CGSizeMake(maxWidth, totalHeight);

return timeStamp;

}


//加载小图

- (CGFloat)loadSubLayers1

{

CGFloat height = 0;

CGFloat maxWidth = 0;

NSDate *begin = [NSDate date];

for (NSString *item in [self.data[@"frames"] allKeys]) {

@autoreleasepool {

NSString *imageName = item;

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:@"png"]];

#ifdef NEEDDRAW

CALayer *layer = [CALayer layer];

layer.contents = (__bridge id _Nullable)(image.CGImage);

layer.frame = CGRectMake(0, height, CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));

layer.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1].CGColor;

height += layer.bounds.size.height;

maxWidth = MAX(maxWidth, layer.frame.size.width);

[self.scrollView.layer addSublayer:layer];

#endif

}

}

NSDate *end = [NSDate date];

CGFloat timeStamp = [end timeIntervalSinceDate:begin];

self.scrollView.contentSize = CGSizeMake(maxWidth, height);

return timeStamp;

}

参考自:iOS-Core-Animation-Advanced-Techniques

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容