显示大图时,传统加载方法会造成内存暴涨,造成主线程阻塞,甚至造成程序crash。可以使用CATiledLayer显示,CATiledLayer类似瓦片视图,他将需要绘制的内容分割成许多小块,然后异步绘制相应的小块,这样就节约了处理时间和内存。
1,它不需要你自己计算分块显示的区域,它自己直接提供,你只需要根据这个区域计算图片相应区域,然后画图就可以了。
2,它是在其他线程画图,不会因为阻塞主线程而导致卡顿。
3,它自己实现了只在屏幕区域显示图片,屏幕区域外不会显示,而且当移动图片时,它会自动绘制之前未绘制的区域,当你缩放时它也会自动重绘。
CATiledLayer是为载入大图造成的性能问题提供的一个解决方案,具体如何划分小块和缩放时的加载策略,与CATiledLayer三个重要属性有关:
levelsOfDetail:levelsOfDetail指的是该图层缓存的缩小LOD数目,默认值为1,每进一级会对前一级分辨率的一半进行缓存,图层的levelsOfDetail最大值,对应至少一个像素点。
levelsOfDetailBias:levelsOfDetailBias指的是该图层缓存的放大LODB数目,它是layer的放大级别重绘设置,默认为0,即不会额外缓存放大层次,每进一级会对前一级两倍分辨率进行缓存。
tileSIze:(默认是256x256)tiledSize是layer划分视图区域最大尺寸,主要是影响layer的切片数量。
+ (Class)layerClass {
return [CATiledLayer class];
}
-(id)initWithFrame:(CGRect)frame image:(UIImage*)img scale:(CGFloat)scale {
if((self= [superinitWithFrame:frame])) {
self.image= img;
_imageRect=CGRectMake(0.0f,0.0f,
CGImageGetWidth(self.image.CGImage),
CGImageGetHeight(self.image.CGImage));
_imageScale= scale;
CATiledLayer*tiledLayer = (CATiledLayer*)[selflayer];
intlev =ceil(log2(1/scale))+1;
tiledLayer.levelsOfDetail=1;
tiledLayer.levelsOfDetailBias= lev;
// tiledLayer.tileSize 此处tilesize使用默认的256x256即可
}
return self;
}
- (void)drawRect:(CGRect)rect {
@autoreleasepool{
CGRectimageCutRect =CGRectMake(rect.origin.x/_imageScale,
rect.origin.y/_imageScale,
rect.size.width/_imageScale,
rect.size.height/_imageScale);
CGImageRefimageRef =CGImageCreateWithImageInRect(self.image.CGImage, imageCutRect);
UIImage*tileImage = [UIImageimageWithCGImage:imageRef];
CGContextRef context = UIGraphicsGetCurrentContext();
UIGraphicsPushContext(context);
[tileImagedrawInRect:rect];
CGImageRelease(imageRef);
UIGraphicsPopContext();
}
}
在GitHub上放了一个demo可以下载https://github.com/love1987/LargeImage。
网友评论