CATiledLayer 大圖分塊展示

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)化記憶。


參考:
https://www.cnblogs.com/v-jing/p/8005224.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谨究,一起剝皮案震驚了整個(gè)濱河市恩袱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胶哲,老刑警劉巖畔塔,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸯屿,居然都是意外死亡澈吨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門寄摆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谅辣,“玉大人,你說我怎么就攤上這事婶恼∩=祝” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵勾邦,是天一觀的道長蚣录。 經(jīng)常有香客問我,道長眷篇,這世上最難降的妖魔是什么萎河? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上虐杯,老公的妹妹穿的比我還像新娘玛歌。我一直安慰自己,他們只是感情好擎椰,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布沾鳄。 她就那樣靜靜地躺著,像睡著了一般确憨。 火紅的嫁衣襯著肌膚如雪译荞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天休弃,我揣著相機(jī)與錄音吞歼,去河邊找鬼。 笑死塔猾,一個(gè)胖子當(dāng)著我的面吹牛篙骡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丈甸,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼糯俗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了睦擂?” 一聲冷哼從身側(cè)響起得湘,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎顿仇,沒想到半個(gè)月后淘正,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡臼闻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年鸿吆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片述呐。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惩淳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乓搬,到底是詐尸還是另有隱情思犁,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布缤谎,位于F島的核電站抒倚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏坷澡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望频敛。 院中可真熱鬧项郊,春花似錦、人聲如沸斟赚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拗军。三九已至任洞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間发侵,已是汗流浹背交掏。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刃鳄,地道東北人盅弛。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像叔锐,于是被迫代替她去往敵國和親挪鹏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345