YYKit--YYLabel源碼分析

一、YYLabel實(shí)現(xiàn)的總體思路

其實(shí)YYLabel主要就是為了實(shí)現(xiàn)異步繪圖,提高性能,為此做了好多東西。

1、使用自定義的Layer,YYAsyncLayer

2、在YYAsyncLayer中實(shí)現(xiàn)異步繪圖,因?yàn)橄到y(tǒng)默認(rèn)的繪圖都是在主線程執(zhí)行了的,這里要實(shí)現(xiàn)異步繪圖,那么就得擯棄掉系統(tǒng)的繪圖方法,自己去實(shí)現(xiàn)。所以這里得花費(fèi)很多功夫。所以說,提高性能是要付出很多的。

二、下面開始進(jìn)入代碼分析:

(1)使用自定義的Layer,YYAsyncLayer

在YYLabel中重寫了下面的方法:

+ (Class)layerClass {

???return [YYAsyncLayer class];

}

就是修改了View的主Layer層,把YYAsyncLayer的實(shí)例作為主Layer層

(2)View與Layer的關(guān)系

View其實(shí)就是Layer的代理,Layer是View的底層實(shí)現(xiàn),View是Layer的管理類。繪圖和坐標(biāo)等操作都是在Layer中實(shí)現(xiàn)的,View只是訪問Layer中的相關(guān)方法。

(3)系統(tǒng)View的繪圖過程:

1、調(diào)用setNeedsDisplay

2、調(diào)用Layer中的display方法

3、在display中會(huì)調(diào)用Layer的drawInContext方法

4、在drawInContext中會(huì)調(diào)用代理方法drawLayer:(CALayer *)layer

inContext:(CGContextRef)ctx,這就進(jìn)入到View了

5、最后View在代理實(shí)現(xiàn)中調(diào)用了drawRect方法,這方法就是我們經(jīng)常用到了那個(gè)。

我寫了demo驗(yàn)證了上面的過程,結(jié)果如下:

(4) YYLabe的繪圖過程

在YYAsyncLayer中,我們找到display方法:

- (void)display {

???super.contents = super.contents;

???[self _displayAsync:_displaysAsynchronously];

}

重寫了display方法,但沒有調(diào)用super方法,就是說上面的流程已經(jīng)被打斷了,那么view的系統(tǒng)繪圖方法都不會(huì)被調(diào)用。

通過代理方法newAsyncDisplayTask得到了YYAsyncLayerDisplayTask類實(shí)例,再通過調(diào)用類實(shí)例的block方法直接返回到View中進(jìn)行操作。作者打斷了之前的繪圖流程,但這里是通過block進(jìn)入到UIView中進(jìn)行繪圖操作,這樣就可以完全控制繪圖過程。

在_displayAsync方法中:

可見,這里是在線程中操作的,先創(chuàng)建了上下文context,然后再調(diào)用代理方法:task.display(context, size,isCancelled),所以UIView在代理實(shí)現(xiàn)中的繪圖操作都是在線程中執(zhí)行的,這里就實(shí)現(xiàn)了異步繪圖。

(5) newAsyncDisplayTask的代理實(shí)現(xiàn)

上面是得到一些繪圖需要的參數(shù),其中最主要的是YYTextLayout對(duì)象,里面包含了很多繪圖需要的信息。

然后是block display方法:

上面提到這個(gè)block實(shí)在非主線程執(zhí)行的,這里執(zhí)行了真正的繪圖操作,繪圖操作方法:

[drawLayoutdrawInContext:context size:size point:point view:nil layer:nil debug:debug cancel:isCancelled];中。

具體的繪圖還是挺復(fù)雜了,看起來(lái)有點(diǎn)吃力,以后有機(jī)會(huì)再研究下。好了,整個(gè)YYLabel的實(shí)現(xiàn)流程已經(jīng)分析完成,是不是覺得源碼作者很牛逼。作者為了實(shí)現(xiàn)異步繪圖,花了好多的功夫。

總結(jié):

所以整體的流程是:首先得理解CALayer與UIView的關(guān)系,UIView就是CALayer的代理,CALayer實(shí)現(xiàn)真正的繪制工作,繪制好之后,再通過代理傳遞到UIView的drawRect方法,給UIView進(jìn)一步繪制的工作,不過UIView也基本不需要在drawRect做什么東西。

YYkit利用這個(gè)原理。自定義了自己的YYLayer和YYLabel,通過在YYLabel上的layerClass關(guān)聯(lián)YYLayer。因?yàn)椴荒苁褂肅ALayer的繪制代碼(UIKit那套是不能在子線程執(zhí)行),所有必須打斷掉以前CALayer的執(zhí)行順序(不讓它使用之前的繪制)。YYKit在YYLayer上重寫了display方法,打斷了以前的順序,讓它不去執(zhí)行之前的繪制。接著在display方法里,通過代理從YYLabel得到一個(gè)task,YYLabel實(shí)現(xiàn)task.display()。YYLayer創(chuàng)建一個(gè)上下文畫板,然后通過在子線程調(diào)用task.display(context)傳遞畫板-context給YYLabel,YYLabel在畫板上用coreGraphic繪制正在的內(nèi)容。繪制好后,在YYLayer上通過主線程返回給layer的self.contents,畫面就展示出來(lái)了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容