0x01 場景分析
當(dāng)我們需要完全展示一張大圖時(shí)(注意不是要做大圖在小容器展示的優(yōu)化)烘豌。就包含了這張大圖在屏幕內(nèi)可以自由滑動(dòng)顯示。
比如大家都用過的地圖辙纬,在展示的時(shí)候是一小塊一小塊進(jìn)行加載的
首先我們知道如果直接使用UIImageView
整個(gè)填充豁遭,那其尺寸與image
尺寸是一樣的。圖片大小會(huì)被整個(gè)加載到內(nèi)存中贺拣,這樣就會(huì)導(dǎo)致內(nèi)存占用非常嚴(yán)重蓖谢,那我們可以怎么處理呢?
iOS
提供了一個(gè)圖層CATiledLayer
來實(shí)現(xiàn)大圖的分塊展示譬涡。
翻譯: Tiled 平鋪闪幽、 瓷磚、 平鋪顯示昂儒、 并列顯示
進(jìn)本的使用思路如下:
1. 使用代碼或者讓UI
設(shè)計(jì)師將大圖切成小圖
2. 使用CATiledLayer
進(jìn)行要展示的區(qū)域圖片繪制
0x02 使用代碼切小圖
以下為可執(zhí)行文件工具代碼沟使,在Mac OS
上運(yùn)行
// main.m
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//從入?yún)⒅凶x取大圖路徑
NSString *inputFile = [NSString stringWithCString:argv[1] encoding:NSUTF8StringEncoding];
// 設(shè)置圖片最大寬高為 256 像素
CGFloat tileSize = 256;
// 指定輸出路徑委可,與入?yún)D片路徑同級(jí)
NSString *outputPath = [inputFile stringByDeletingPathExtension];
//加載圖片
NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputFile];
NSSize size = [image size];
NSArray *representations = [image representations];
if ([representations count]){
NSBitmapImageRep *representation = representations[0];
size.width = [representation pixelsWide];
size.height = [representation pixelsHigh];
}
NSRect rect = NSMakeRect(0.0, 0.0, size.width, size.height);
CGImageRef imageRef = [image CGImageForProposedRect:&rect context:NULL hints:nil];
//calculate rows and columns
NSInteger rows = ceil(size.height / tileSize);
NSInteger cols = ceil(size.width / tileSize);
for (int y = 0; y < rows; ++y) {
for (int x = 0; x < cols; ++x) {
//extract tile image
CGRect tileRect = CGRectMake(x*tileSize, y*tileSize, tileSize, tileSize);
CGImageRef tileImage = CGImageCreateWithImageInRect(imageRef, tileRect);
// 轉(zhuǎn)換為jpg圖片
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:tileImage];
NSData *data = [imageRep representationUsingType: NSJPEGFileType properties:nil];
CGImageRelease(tileImage);
// 保存文件至輸出目錄
NSString *path = [outputPath stringByAppendingFormat: @"_%02i_%02i.jpg", x, y];
[data writeToFile:path atomically:NO];
}
}
}
return 0;
}
0x03 使用CATiledLayer
展示
以下為iOS
項(xiàng)目代碼
@interface ViewController ()<CALayerDelegate>
// 構(gòu)建一個(gè)容器來展示大圖渊跋,保證其contenSize與圖片尺寸大小一致
@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建圖層,并設(shè)置屬性信息
CATiledLayer *tileLayer = [CATiledLayer layer];
CGFloat scale = UIScreen.mainScreen.scale; // 確保scale比例一致
tileLayer.frame = CGRectMake(0, 0, 3972/scale,15718/scale);// 圖片像素
tileLayer.delegate = self;
tileLayer.tileSize = CGSizeMake(256/scale, 256/scale); // 每個(gè)瓷磚塊的大小
tileLayer.delegate = self;
[self.scrollView.layer addSublayer:tileLayer];
self.scrollView.contentSize = tileLayer.frame.size;
// 刷新當(dāng)前屏幕Rect
[tileLayer setNeedsDisplay];
}
// 當(dāng)滑動(dòng)到不同區(qū)域時(shí)會(huì)調(diào)用此方法
- (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)ctx
{
// 確定坐標(biāo)信息
CGRect bounds = CGContextGetClipBoundingBox(ctx);
NSInteger x = floor(bounds.origin.x / layer.tileSize.width);
NSInteger y = floor(bounds.origin.y / layer.tileSize.height);
// 加載小圖
NSString *imageName = [NSString stringWithFormat: @"zz_%02i_%02i", x, y];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"jpg"];
UIImage *tileImage = [UIImage imageWithContentsOfFile:imagePath];
// 在TiledLayer上繪制圖片
UIGraphicsPushContext(ctx);
[tileImage drawInRect:bounds];
UIGraphicsPopContext();
}
0x03 其他屬性
產(chǎn)生模糊的根源是圖層的細(xì)節(jié)層次(level of detail
着倾,簡稱LOD
)
-
levelsOfDetail
:
縮小視圖是拾酝,最大可以達(dá)到的縮小級(jí)數(shù)。指圖層維護(hù)的
LOD
數(shù)目卡者,默認(rèn)值為1
蒿囤,每進(jìn)一級(jí)會(huì)對(duì)前一級(jí)分辨率的一半進(jìn)行緩存,圖層的levelsOfDetail
最大值崇决,也就是最底層細(xì)節(jié)材诽,對(duì)應(yīng)至少一個(gè)像素點(diǎn)底挫。 -
levelsOfDetailBias
:
從最小視圖需要放大多少次,才能達(dá)到我們需要的清晰度效果脸侥,注意是多少次建邓,一次就是2倍指的是該圖層緩存的放大
LOD
數(shù)目,默認(rèn)為0
睁枕,即不會(huì)額外緩存放大層次官边,每進(jìn)一級(jí)會(huì)對(duì)前一級(jí)兩倍分辨率進(jìn)行緩存。 tileSize
: 用于創(chuàng)建層內(nèi)容的每個(gè)平鋪的最大大小外遇,默認(rèn)為256*256
注簿。
需要注意下,如果tileSize
設(shè)置太小就會(huì)把每塊瓷磚圖片展示的很小
0x04 總結(jié)
大圖展示跳仿,越是尺寸比較大诡渴,像素比較高,在性能優(yōu)化時(shí)得到的效果就越明顯菲语。
本文并無深度僅作為隨筆記錄這塊功能的基本使用玩徊,便于后續(xù)強(qiáng)化記憶。