iOS7 之前,幾乎所有的復雜文本都是通過 WebKit 來處理的,無論 UILabel、UITextField 還是 UITextView 都在后臺以某種方式使用 webViews 來進行文本布局和渲染。iOS7 以后,蘋果提供了 TextKit 對文本進行操作,并且對 UILabel、UITextField、UITextView 都利用 TextKit 進行了改造。
前言
TextKit 簡介
TextKit是蘋果提供的一系列用于文字排版服務的類和協(xié)議的集合,能夠幫助 app 存儲、布局和展示文本。TextKit 是以 CoreText 為基礎構建的,所以能夠提供與 CoreText 相同的性能和能力。下圖展示了 TextKit 與 iOS 中其他文本和圖形框架的相互關系:

Text Kit 框架結構
TextKit 在界面展示方面提供給了開發(fā)者在文本渲染之上的全部權限。
TextKit 中主要的類
TextKit 中主要包括三個類:NSTextStorage、NSLayoutManager 以及 NSTextContainer,這三個主要的類與 view 之間的關系如下圖:

Text Kit 主要類之間的關系
-
NSTextStorage是整個文本系統(tǒng)的數據來源,其管理著文本和文本屬性信息,它是NSMutableAttributedString的一個子類。 -
NSTextContainer定義了一個可以布局文本的區(qū)域,并且也可以通過設置一個貝塞爾曲線數組的方式來為編輯區(qū)域設置排除區(qū)域,每個 Text View 都有一個 Text Container,它精確地描述了這個可用的區(qū)域。 -
NSLayoutManager對文本系統(tǒng)的其他部分起到協(xié)調作用,將NSTextStorage中存儲的文本信息渲染到視圖的展示區(qū)域。NSLayoutManager的工作主要包括以下幾個方面:監(jiān)聽 Text Storage 中文本或屬性改變的通知,一旦接收到通知就觸發(fā)布局進程;將NSTextStorage中所有的字符翻譯為字形;向它的 TextContainers 查詢文本可用以繪制的區(qū)域;這些區(qū)域被行逐步填充,而行又被字形逐步填充。一旦一行填充完畢,下一行開始填充;對于每一行,布局管理器必須考慮斷行行為(放不下的單詞必須移到下一行)、連字符、內聯的圖像附件等等;當布局完成,文本的當前顯示狀態(tài)被設為無效,然后 Layout Manager 將前面幾步排版好的文本設給 Text View。
TextKit 中各主要部分之間的關系如下圖所示:

TextKit 中各主要部分
以編程的方式修改一個NSTextStorage對象主要有三個階段:
- 向
NSTextStorage對象發(fā)送beginEditing消息來開啟接下來的一系列修改; - 通過
replaceCharactersInRange:withString:和setAttributes:range:方法來修改對象中存儲的字符或者字符屬性,每次在調用這些方法的時候,textStorage 對象都會自動的調用edited:range:changeInLength:方法; - 修改結束后,發(fā)送
endEditing消息,這樣會使 textStorage 對象向代理發(fā)送消息
textStorage:willProcessEditing:range:changeInLength:
并且調用對象本身的processEditing方法,之后向代理對象發(fā)送textStorage:didProcessEditing:range:changeInLength:
消息,最后, textStorage 對象會向其相關聯的 layout manager 對象發(fā)送
processEditingForTextStorage:edited:range:changeInLength:invalidatedRange:消息,所有相關聯的 layout manager 會輪流通過這個消息重新計算字形位置。