iOS - YYKit 之 YYText

本文只是讓自己加深下理解,方便以后查看,原作者看到有不合適的地方,或者大神們看到有不對(duì)的地方希望指正 ~

原文地址,尊重原作者 ~

<br />

一. 特點(diǎn)和用法

關(guān)于YYText的特點(diǎn)和用法請(qǐng)看@ibireme大神的github

二. 使用到的組件

  1. 介紹YYLabel之前先說(shuō)一下YYTextAttribute,因?yàn)楹竺鏁?huì)大量的使用到它。
    YYTextAttribute

  2. 定義的一些Enum,
    YYTextAttributeType: attribute的類型,有None、UIKit、CoreTextYYText四種類型;
    YYTextLineStyleline的樣式;
    YYTextVerticalAlignment: 垂直方向text的位置;
    YYTextDirectiontext的位置;
    YYTextTruncationTypetext截?cái)嗟奈恢谩?/p>

  3. YYText中定義的Attribute Name。主要是獨(dú)有的一些類型。

  4. YYTextBackedString:可以將一些表情圖片映射成純文本。

  5. YYTextBinding:使一些特定的字符串綁定在一起,YYTextView在選擇和編輯他們的時(shí)候把他們當(dāng)成一個(gè)單獨(dú)的字符。

  6. YYTextShadow:用處和NSShadow一樣,只是比NSShadow多了一些功能,比如說(shuō)可以使用blendMode(圖形混合模式)、可以在shadow上再加一層shadow。關(guān)于blendMode的學(xué)習(xí),可以參見(jiàn)喵神的博客

  7. YYTextDecoration:實(shí)現(xiàn)下劃線(underline)和中間截線(strikethrough)時(shí)使用,線條的形式給出了幾種樣式,可以通過(guò)YYTextLineStyle枚舉查看。具體是underline還是strikethrough是在NSAttributedString+YYText中NSMutableAttributeString(YYText)中實(shí)現(xiàn)的方法。

  8. YYTextBorder:實(shí)現(xiàn)在文本周圍畫一個(gè)border,也可以是填充一個(gè)背景色。

  9. YYTextAttachment:封裝需要放入text中的對(duì)象。在說(shuō)明文檔中提到,如果attachmentUIImage,就繪制到CGContext,如果是UIView或者CALayer就加入到text container的view或者layer中。

  10. YYTextHightlight:當(dāng)YYLabel或者YYTextView中的text可以被用戶按下時(shí),被按下的text會(huì)有一個(gè)highlighted 狀態(tài),這時(shí)候就需要是用YYTextHighlight來(lái)修改原來(lái)的text。所以這個(gè)對(duì)象和YYText一樣,只是是在highlight狀態(tài)下的YYText,而且添加了點(diǎn)擊和長(zhǎng)按事件。

  11. 再來(lái)說(shuō)一下NSAttributedString+YYText文件
    在這個(gè)分類中主要是實(shí)現(xiàn)了幾類的操作:

  12. 一些操作當(dāng)前attributed string的方法
    比如說(shuō)歸檔和反歸檔當(dāng)前字符串、獲得某個(gè)位置的attributes、字間距、色值、背景色、shadow等等。具體的參見(jiàn)文件,基本上是作者封裝的方便獲得各種數(shù)據(jù)的方法。(和Foundation比強(qiáng)大太多了)。

  13. YYText創(chuàng)建attachment的方法

  14. YYText添加YYText特有的attribute的方法

  15. 添加像設(shè)置屬性一樣的設(shè)置character attribute的font、colorbackgroundColor等等的方法

  16. 添加像設(shè)置屬性一樣的設(shè)置paragraph attribute的方法。

  17. 添加像設(shè)置屬性一樣的設(shè)置YYText attribute的方法。

  18. 使用range設(shè)置不連續(xù)的attribute的方法

  19. 設(shè)置text highlight的便捷方法

  20. 和其他的工具型的方法。

  21. NSParagraphStyle+YYText文件
    提供了CoreText中的CTParagraphStyleRefNSParagraphStyle之間的轉(zhuǎn)化

  22. YYTextParser
    這是一個(gè)protocol,聲明了一個(gè)-(BOOL)parseText:(NSMutableAttributedString *)string selectedRange:(NSRangePointer)selectedRange;方法。這個(gè)方式是遵守這個(gè)協(xié)議必須實(shí)現(xiàn)的方法,當(dāng)YYTextView或者YYLabel中的text改變時(shí)被調(diào)用。返回YES說(shuō)明修改了這個(gè)text。
    作者簡(jiǎn)單的實(shí)現(xiàn)了MarkdownParserEmotionParser,兩個(gè)原理都差不多一樣,在這里只對(duì)EmotionParser做一下簡(jiǎn)單的介紹,希望能有所啟發(fā):


    這段代碼(上圖)就是生成正則表達(dá)式_regex和映射的字典_mapper,第一層for是獲得你要匹配的key,第二層是如果有這些特殊的字符需要轉(zhuǎn)譯一下,然后將這些需要比配的key 用“|”連接起來(lái)。

    這個(gè)(上圖)就是修改text之后會(huì)被調(diào)用的方法,在這個(gè)方法里對(duì)輸入的text進(jìn)行匹配,如果匹配到之前_mapper中需要替換的字符,就將這個(gè)字符串替換為需要替換的表情符。

    替換成表情符之后就需要重新計(jì)算這個(gè)表情符所占的range了,這個(gè)方法就是拿到替換之后的的range。

5.YYTextLayout

先看一下文檔中的說(shuō)明,如下圖:


是不是很眼熟?好像在哪見(jiàn)過(guò)?是的,就是NSLayoutManager和NSTextContainer。他們的作用都是相似的。

  1. YYTextContainer
    支持矩形(CGSize)和圖形(UIBezierPath)來(lái)初始化YYTextContainer;
    在這里重點(diǎn)說(shuō)一下YYTextLinePositionModifier,它是 一個(gè)協(xié)議,定義了一個(gè)必須實(shí)現(xiàn)的方法,這個(gè)方法將會(huì)在layout完成的時(shí)候被調(diào)用,三個(gè)參數(shù)分別是存放YYTextLine的數(shù)組、完整的textlayout container。
    YYTextLine:它是封裝了CTLineRef的對(duì)象,封裝了每一行text的具體展示位置、range、這一行擁有的attachments等等,只有一個(gè)類方法的初始化方法。如果不了解一些自行描述集的內(nèi)容,對(duì)textLine中的一些屬性和操作會(huì)不是很清晰,看下圖:


    邊框(Bounding Box):一個(gè)假想的邊框,盡可能地容納整個(gè)字形。
    基線(Baseline):一條假想的參照線,以此為基礎(chǔ)進(jìn)行字形的渲染。一般來(lái)說(shuō)是一條橫線。
    基礎(chǔ)原點(diǎn)(Origin):基線上最左側(cè)的點(diǎn)。
    行間距(Leading):行與行之間的間距。
    字間距(Kerning):字與字之間的距離,為了排版的美觀,并不是所有的字形之間的距離都是一致的,但是這個(gè)基本步影響到我們的文字排版。
    上行高度(Ascent)和下行高度(Decent):一個(gè)字形最高點(diǎn)和最低點(diǎn)到基線的距離,所以行高就是ascent + decent。
    看完上面的簡(jiǎn)單介紹你就能明白,在YYTextLinesetCTLine中的代碼邏輯是從CTLineRef中取出對(duì)應(yīng)的行寬、上行高度、下行高度、行間距、rangge和第一個(gè)字型符的位置(這個(gè)在垂直布局會(huì)用到)。之后調(diào)用reloadBounds方法,重新計(jì)算當(dāng)前行的boundsattachments所在的rangerect
  2. YYTextLayout
    這個(gè)真的是核心內(nèi)容了,這個(gè)文件一共3300多行的代碼,從代碼量上就能看出它的地位。這個(gè)類中存儲(chǔ)著 textlayout結(jié)果,所有的property都是readonly的。實(shí)現(xiàn)的接口有:
    1、通過(guò)一些類方法初始化的方法(YYTextContainerCGSizetext
    2、layout之后的attributes,都是只讀的
    3、從layout中讀取信息(位置、range等等)
    4、繪制text layout
    這個(gè)類主要是使用上面講過(guò)的所有的數(shù)據(jù)來(lái)繪制text,這部分的代碼還是需要一點(diǎn)一點(diǎn)的去讀的,如果是新手每一行都會(huì)有收獲(比如說(shuō)我),如果是老司機(jī)就沒(méi)有必要一行行的讀了,了解他的解題思路和解決這個(gè)問(wèn)題的辦法就可以。下面說(shuō)一下生成layout的那個(gè)500行代碼的情況,就按照代碼的順序從上往下大概的說(shuō)明一下干了什么。
* 1)、初始化一系列使用到的變量

2)、安全判斷,textcontainer
3)、判斷是否需要修復(fù)emoji的bug(iOS8.3中)
4)、判斷是否設(shè)置了path屬性和exclusionPaths數(shù)組,做相應(yīng)的計(jì)算拿到CGPath,如果CGPath為空則goto fail 返回nil(如果設(shè)置了path,sizeinsets就沒(méi)有用了)
5)、判斷是不是奇偶填充,判斷pathWidth是否為0,判斷是否是垂直展示
6)、使用text創(chuàng)建CTFramesetterRef,創(chuàng)建失敗goto fail
7)、使用上一步中創(chuàng)建的frameSetter創(chuàng)建CTFrameRef
8)、從CTFrameRef的對(duì)象中獲得每一行、ctRun數(shù)組,計(jì)算每一行的frame,判斷是否實(shí)現(xiàn)了linePositionModifier這個(gè)協(xié)議,有的話調(diào)用協(xié)議方法。
9)、計(jì)算bounding size
10)、判斷是否需要truncation,和按那種方式處理
11)、判斷是否垂直布局text,需要的話,旋轉(zhuǎn)布局
12)、判斷得到的visibleRange長(zhǎng)度,有效的話遍歷text中的attributes,配置對(duì)應(yīng)的layout屬性
13)、配置layout中attachments
14)、配置結(jié)束,返回layout
繪制時(shí)就是根據(jù)layout中的配置情況繪制相應(yīng)的特征,這段代碼在此就不做分析了。

6.YYAsyncLayer文件

YYAsyncLayerDispalyTask是在YYAsyncLayerbackground queue渲染是調(diào)用的對(duì)象,它有三個(gè)回調(diào),一個(gè)willDisplay在渲染之前、一個(gè)didDisplay在渲染之后和渲染時(shí)被調(diào)用的display。

YYAsyncLayerCAlayer的子類,當(dāng)這個(gè)layer更新contents時(shí)就會(huì)調(diào)用delegate方法去調(diào)用async display taskbackground queue 渲染。這個(gè)delegate方法是YYAsyncLayerDelegate的方法。

YYAsyncLayer刷新時(shí)調(diào)用_displayAsync:方法,然后調(diào)用遵守YYAsyncLayerDelegate的對(duì)象實(shí)現(xiàn)的newAsyncDisplayTask方法,獲取到需要繪制的前后和繪制時(shí)的task,根據(jù)是夠需要異步來(lái)判斷直接在主線程執(zhí)行繪制代碼還是異步執(zhí)行繪制代碼。

在異步繪制過(guò)程中用到了一個(gè)異步隊(duì)列,獲取方法是YYAsyncLayerGetDisplayQueue,在這個(gè)方法中有一個(gè)關(guān)于QOS的概念,NSQualityOfService(QOS) ios8之后提供的新功能,這個(gè)枚舉值是要告訴操作系統(tǒng)我們?cè)谶M(jìn)行什么樣的工作,讓系統(tǒng)能通過(guò)合理的資源控制來(lái)最高效的執(zhí)行任務(wù)代碼,主要涉及CPU調(diào)度、IO優(yōu)先級(jí)、任務(wù)運(yùn)行在哪個(gè)線程以及運(yùn)行的順序等等。

枚舉值的含義如下

NSQualityOfServiceUserInteractive 與用戶交互的任務(wù),這些任務(wù)通常跟UI級(jí)別的刷新相關(guān),比如動(dòng)畫,這些任務(wù)需要在一瞬間完成

NSQualityOfServiceUserInitiated 由用戶發(fā)起的并且需要立即得到結(jié)果的任務(wù),比如滑動(dòng)scroll view時(shí)去加載數(shù)據(jù)用于后續(xù)cell的顯示,這些任務(wù)通常跟后續(xù)的用戶交互相關(guān),在幾秒或者更短的時(shí)間內(nèi)完成

NSQualityOfServiceUtility 一些可能需要花點(diǎn)時(shí)間的任務(wù),這些任務(wù)不需要馬上返回結(jié)果,比如下載的任務(wù),這些任務(wù)可能花費(fèi)幾秒或者幾分鐘的時(shí)間

NSQualityOfServiceBackground 這些任務(wù)對(duì)用戶不可見(jiàn),比如后臺(tái)進(jìn)行備份的操作,這些任務(wù)可能需要較長(zhǎng)的時(shí)間,幾分鐘甚至幾個(gè)小時(shí)

NSQualityOfServiceDefault 優(yōu)先級(jí)介于user-initiated 和 utility,當(dāng)沒(méi)有 QoS信息時(shí)默認(rèn)使用,開(kāi)發(fā)者不應(yīng)該使用這個(gè)值來(lái)設(shè)置自己的任務(wù)

Qos和GCD queue的對(duì)照?qǐng)D:


看詳細(xì)的分析請(qǐng)點(diǎn)這里

收獲到的小知識(shí)點(diǎn)

  1. iOS7 and later,UIFontCTFontReftoll-free bridged的,在iOS6,UIFont是對(duì)CTFontRref的封裝,所以在CoreText中是可以使用UIFont的,但是在UILabelUITextView中不能使用CTFontRef。
  2. NSParagraphStype不是toll-free bridged 到CTParagraphStypeRef,CoreText可以同時(shí)使用兩者,但UILabelUITextView只能使用NSParagraphStyle。
  3. 查看.a靜態(tài)文件支持哪種iOS處理器
最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

  • YYKit之YYText 轉(zhuǎn)載鏈接: http://www.cnblogs.com/lujianwenance/p...
    kakukeme閱讀 4,704評(píng)論 3 51
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,733評(píng)論 25 709
  • 內(nèi)容來(lái)自于 iOS文檔中 About Text Handling in iOS 部分 ios平臺(tái)提供了顯示及編輯文...
    縱橫而樂(lè)閱讀 7,131評(píng)論 2 21
  • 練習(xí)新聞聽(tīng)力不能著急,用心去體會(huì)單詞
    班克西閱讀 178評(píng)論 0 0
  • 爸 媽 我近視了 一副又一副眼鏡 太陽(yáng)穴被壓得不行 你們給我指的路還是看不清 好幾次我摘下眼鏡 就像個(gè)瞎子 無(wú)法前行
    小年糕菌閱讀 150評(píng)論 0 0

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