内容简介:最近碰到一个需求,显示一张超大图首先就想到了使用Core Animation框架进行画图,其实我对这个框架也不是十分了解,只是了解过CALayer,以及使用drawRect画图。于是我就遇到了第一个问题,就是在比较大的frame内绘图时内存爆炸,超过50M的图也会Crash,这个问题也很好解决,就是将它分块显示,做一个循环,计算分块区域,分别显示图片相应的区域
最近碰到一个需求,显示一张超大图
以下是我自己的分析和尝试,不想看的话可以直接跳过看下面的CATiledLayer介绍
首先就想到了使用Core Animation框架进行画图,其实我对这个框架也不是十分了解,只是了解过CALayer,以及使用drawRect画图。
于是我就遇到了第一个问题,就是在比较大的frame内绘图时内存爆炸,超过50M的图也会Crash,这个问题也很好解决,就是将它分块显示,做一个循环,计算分块区域,分别显示图片相应的区域
第二个问题就是在放大重绘时会卡顿,一点都不流畅,而且内存也会暴增,在尝试过将重绘代码放进@autoreleasepool后,仍然不太流畅不过内存减少了(尝试过添加多线程,但是不能实时更新视图)。
经过分析后,第二个问题主要原因是无论放到多大,重绘仍会将图片全部绘制出来,但是我们在屏幕上是只看到图片的部分区域,如下图
所以只需要显示图片在屏幕的区域就可以了,在循环中加上判断绘制区域是否在屏幕上,是的话就绘制,不是的话就不绘制
我的分析和尝试就到这里,下面进入正题
在这里提出一个问题,
在CALayer的drawRect中是否可以使用多线程绘图,如何使用?
CATiledLayer介绍
其实在我遇到上面的第二个难题的时候就在网上搜索解决方法,才了解到这个神器,根据这个layer的机制,才有了第二个难题的解决方案。
CATiledLayer类似瓦片视图,可以将绘制分区域进行,常用于一张大的图片的分部绘制,如图。
使用这个layer的好处之一就是,它不需要你自己计算分块显示的区域,它自己直接提供,你只需要根据这个区域计算图片相应区域,然后画图就可以了。
第二个好处就是它是在其他线程画图,不会因为阻塞主线程而导致卡顿。
第三个好处就是它自己实现了只在屏幕区域显示图片,屏幕区域外不会显示,而且当移动图片时,它会自动绘制之前未绘制的区域,当你缩放时它也会自动重绘。
下面是使用方法
首先是改变视图的Layer类
+(Class)layerClass{
return [CATiledLayer class];
}
然后在drawRect函数添加以下代码
-(void)drawRect:(CGRect)rect {
//将视图frame映射到实际图片的frame
CGRect imageCutRect = CGRectMake(rect.origin.x / imageScale,rect.origin.y / imageScale,rect.size.width / imageScale,rect.size.height / imageScale);
//截取指定图片区域,重绘
CGImageRef imageRef = CGImageCreateWithImageInRect(originImage.CGImage, imageCutRect);
UIImage *tileImage = [UIImage imageWithCGImage:imageRef];
CGContextRef context = UIGraphicsGetCurrentContext();
UIGraphicsPushContext(context);
[tileImage drawInRect:rect];
UIGraphicsPopContext();
}
其中imageScale是当前视图Size和图片Size的比例,通过这个和rect可以计算出实际图片的裁切区域。
CGFloat imageScale = self.frame.size.width/imageRect.size.width;
现在这要载入一张图片就可以运行。
下面我们载入一张200M的大图(30000*18840)进行分析
如图,是默认的切片,没有对CATiledLayer的tileSIze(默认是256x256)进行设置
在默认的tileSize下,会将视图分割成6块进行绘制,可以看到在绘制过程中,内存飙升到500多M,这个主要原因是一次切割的图片还是太大了,在绘制完成后内存回落。
下面对tileSize进行设置,首先是将它赋值成视图的大小
tiledLayer.tileSize = self.bounds.size;
看图
可以看到设置成tileSize视图大小后,视图分割成4块,内存飙升到700多M,这是当然的,tileSize变成了(375x235.5)分割的图片尺寸变大了。
我们试一试将tileSize缩小两倍
CGSize tileSize = self.bounds.size; tileSize.width /=2; tileSize.height/=2; tiledLayer.tileSize = tileSize;
看图
可以看到缩小2倍后,视图分割成16块,内存下降到200多M,因为分割的尺寸变小了。
那么要达到峰值在100M以下就变得很简单了,我们把tileSize缩小5倍看看
哈哈,内存峰值降低到60多M,给自己双击666
我们再看一看缩放效果
可以看到,每次缩放都会重绘,而且它只会绘制屏幕区域内的图片。
总结一下,tiledSize的设置主要是影响CATiledLayer的切片数量,想自己控制数量的话,需要将它设置成视图的size倍数,当然如果你找到它的其他size规律的话也可以自己定义。
在这里感谢
-
刘冰:Core Animation简介(二)
-
vvGo:iOS 超大高清图展示策略 TileLayer 及 levelsOfDetailBias 分析
问题1:怎么实现缩小到一定size,CATiledLayer不再重绘?
最后附上Demo
如有任何疑问请留言或者联系邮箱289193866@qq.com
如有错漏请提出指正谢谢
作者:小点草
链接:https://www.jianshu.com/p/ee0628629f92
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 快手超大规模集群调度优化实践
- MySQL自增id超大问题查询
- 超大屏数据可视化总结-智慧城市
- 超大7k高清显示器显示网页解决方案
- 超大文件上传之计算文件MD5值
- PHP超低内存遍历目录文件和读取超大文件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beautiful Code
Greg Wilson、Andy Oram / O'Reilly Media / 2007-7-6 / GBP 35.99
In this unique work, leading computer scientists discuss how they found unusual, carefully designed solutions to difficult problems. This book lets the reader look over the shoulder of major coding an......一起来看看 《Beautiful Code》 这本书的介绍吧!