iOS 圖形繪制方案

先說下背景夹攒,項(xiàng)目里需要繪制音樂和視頻的波形圖,由于產(chǎn)品上的設(shè)計(jì)胁塞,波形圖的長度基本都可以達(dá)到屏幕長度的幾十倍咏尝。并且圖形并不是折線圖而是柱狀圖,還要跟隨音樂音量變化啸罢,所以圖形肯定是無法直接拉伸擠壓的编检,所以當(dāng)時(shí)為了性能和內(nèi)存方面的考慮,嘗試了很多方案扰才。

UIImage:
使用UIGraphicsGetImageFromCurrentImageContext方法將繪制的圖形生成圖片允懂。
這種方式適用于圖片不長并且圖片不變的情況。

優(yōu)點(diǎn):可在子線程繪制衩匣,方便緩存蕾总。
缺點(diǎn):占用內(nèi)存大,繪制不夠高效琅捏。
PS:注意此方法有個(gè)隱患生百,因?yàn)橄到y(tǒng)會(huì)對設(shè)置給UIImageView的圖片進(jìn)行緩存,如果一直調(diào)用柄延,即使是完全相同的圖片蚀浆,也會(huì)產(chǎn)生內(nèi)存占用。
示例:

- (UIImage*) drawImageFromCreaterWithMinValue:(int)minValue
                                     MaxValue:(int)maxValue {
    CGSize imageSize = CGSizeMake(imageWidth, imageHeigh);
    
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //假裝有繪制代碼
    …………………………
   
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;

CALayer :
layer的基類搜吧,重寫drawInContext方法進(jìn)行進(jìn)行繪制市俊。
優(yōu)點(diǎn):量級輕(實(shí)在想不到優(yōu)點(diǎn))。
缺點(diǎn):主線程繪制赎败,繪制不夠高效 秕衙。
示例:

//子類重寫drawInContext方法
- (void)drawInContext:(CGContextRef)ctx {
    UIGraphicsPushContext(ctx);
    [self drawSomthing];
    UIGraphicsPopContext();
}

CATiledLayer:
layer的子類,專門用于繪制大圖的方案僵刮,系統(tǒng)底層已進(jìn)行過優(yōu)化据忘,子線程繪制,并且不會(huì)繪制屏幕外的內(nèi)容搞糕∮碌酰可將大圖分割成若干個(gè)更小的單元進(jìn)行繪制,可通過tileSize設(shè)置單個(gè)繪制單元的大小窍仰。
優(yōu)點(diǎn):子線程繪制汉规,性能極好。
缺點(diǎn):繪制較緩慢,能控制的變量較少针史。
示例:

與CALayer用法一致晶伦,可設(shè)置額外屬性

    CGSize tileSize = CGSizeMake(w, h);
    layer.tileSize = tileSize;   //設(shè)置單次繪制的單元

YYAsyncLayer:
知名的異步繪制的第三方控件,是CALayer的子類啄枕,內(nèi)部創(chuàng)建了隊(duì)列進(jìn)行管理婚陪,能將繪制的操作轉(zhuǎn)換為異步操作,并且引入了RunLoop機(jī)制進(jìn)行管理频祝,只在RunLoop空閑的時(shí)候才進(jìn)行刷新操作泌参。
優(yōu)點(diǎn):子線程繪制,性能很高常空,不阻塞用戶操作沽一。
缺點(diǎn):因?yàn)橹辉诳臻e時(shí)執(zhí)行,圖形刷新不及時(shí)漓糙。
示例:

+ (Class)layerClass {
    return YYAsyncLayer.class;
}

- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask {
    
    YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new];
    task.willDisplay = ^(CALayer *layer) {
        //...
    };
    
    
    __weak typeof(self) weakSelf = self;
    task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) {
        if (isCancelled()) return;
          //繪制的代碼寫在這里
    };
    
    task.didDisplay = ^(CALayer *layer, BOOL finished) {
        if (finished) {
            // finished
        } else {
            // cancelled
        }
    };
    
    return task;
}

CAShapeLayer + UIBezierPath:
layer的子類铣缠,CAshapeLayer能在GPU上渲染,性能很高昆禽,繪制速度很快攘残,而且曲線繪制既能選擇在主線程繪制,也能選擇在子線程繪制为狸。
優(yōu)點(diǎn):無論子線程還是主線程都可繪制,且性能很高遗契。
缺點(diǎn):曲線路徑量大的話辐棒,還是影響性能。
示例:

    UIBezierPath*  wavePath = [self drawLayerPath];
    CAShapeLayer *shaperlayer = [[CAShapeLayer alloc]init];
    shaperlayer.path = wavePath.CGPath;

最終還是選擇了CAShapeLayer + UIBezierPath方案牍蜂,但是因?yàn)橐舨〝?shù)據(jù)量特別大(每秒40個(gè)音頻數(shù)據(jù))漾根,導(dǎo)致多個(gè)圖形頻繁刷新的時(shí)候發(fā)熱十分嚴(yán)重,而且也出現(xiàn)了卡頓的情況鲫竞。
為了優(yōu)化辐怕,最后又加入了分屏繪制的邏輯:


QQ20200819-152747@2x.png

藍(lán)色區(qū)域表示屏幕區(qū)域,紅色表示繪制的區(qū)域从绘,黑色線條表示臨界邊寄疏,
整體邏輯:
0、轉(zhuǎn)換坐標(biāo)為窗體坐標(biāo)僵井。
1陕截、判斷是否有上次繪制的位置,沒有則直接繪制批什。
2农曲、繪制完成后保存當(dāng)前位置為繪制位置,計(jì)算出黑色臨臨界區(qū)域驻债。
3乳规、滑動(dòng)視圖的過程中判斷滑動(dòng)位置是否超出了黑線區(qū)域形葬,超出則重新進(jìn)行繪制。
4暮的、重復(fù)2笙以、3。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末青扔,一起剝皮案震驚了整個(gè)濱河市源织,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌微猖,老刑警劉巖谈息,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凛剥,居然都是意外死亡侠仇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門犁珠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逻炊,“玉大人,你說我怎么就攤上這事犁享∮嗨兀” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵炊昆,是天一觀的道長桨吊。 經(jīng)常有香客問我,道長凤巨,這世上最難降的妖魔是什么视乐? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮敢茁,結(jié)果婚禮上佑淀,老公的妹妹穿的比我還像新娘。我一直安慰自己彰檬,他們只是感情好伸刃,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逢倍,像睡著了一般奕枝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瓶堕,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天隘道,我揣著相機(jī)與錄音,去河邊找鬼。 笑死谭梗,一個(gè)胖子當(dāng)著我的面吹牛忘晤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播激捏,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼设塔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了远舅?” 一聲冷哼從身側(cè)響起闰蛔,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎图柏,沒想到半個(gè)月后序六,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚤吹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年例诀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裁着。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡繁涂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出二驰,到底是詐尸還是另有隱情扔罪,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布桶雀,位于F島的核電站步势,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏背犯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一盅抚、第九天 我趴在偏房一處隱蔽的房頂上張望漠魏。 院中可真熱鬧,春花似錦妄均、人聲如沸柱锹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽禁熏。三九已至,卻和暖如春邑彪,著一層夾襖步出監(jiān)牢的瞬間瞧毙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宙彪,地道東北人矩动。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像释漆,于是被迫代替她去往敵國和親悲没。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345