最近要作一個讀入Word,PDF格式等的文件而且加以編輯的程序,原本覺得使用Text Kit結合Text View來打開doc文件是徹底沒問題的,結果用了各類方法打開要麼是數據是nil,要麼打開的文字中不少亂碼。對於Word,PDF這種格式或許必需要用底層的Core Text來作了(若是用WebView來作的話,很難對內容進行操做)。框架
因此接下來又要從Core Text從頭學起了。首先看了Core Text Programming Guide,理解的並不算深刻,可是寫個博客來作個筆記吧。ide
Core Text是一個iOS中一個比較底層的框架,借用iOS7 Text Kit介紹視頻中的一個圖:佈局
其中Core Text在Core Graphics之上,Text Kit在Core Text之上構建(UIWebView不在Text Kit之上,不少Text Kit中很棒的特性UIWebView沒法使用)。學習
在文檔中,Core Text被描述爲一個高級的、底層的框架,主要用來對文本進行排版佈局和字體處理。字體
Core Text有一個很強大的功能就是進行Character-to-glyph轉換,其實以前看Text Kit的時候glyph這個詞就是一個高頻出現的詞,我的以爲必需要分清楚character,glyph,font這些概念之間的分別。ui
按照我的的理解(語文很差,說錯了請指出):spa
(1)character:字符,指一個符號,數字或者文字等。.net
(2)glyph:字形,對於同一套字符有不一樣的寫法,形態或者說是樣式。字形是字符的一族形態,例如Helvetica, New Romancode
(3)font:字體,在字形的基礎上進行的加工修飾便構成了字體,如加粗,傾斜,加顏色,改變磅數等。例如orm
9pt Helvetica Bold是一個字體。
回到文檔來看看Character-to-glyph conversion:
對應同一個字符A,有着各類不一樣的形態,對應不一樣的字形glyph,固然同一種風格的寫法便構成了一種字形。
一樣地,對於f加l兩個字符連起來寫便又變成了一種新的寫法,對應另一種字形。
經過Core Text能夠快速高效地進行字符到字形之間的轉換。
使用Core Text能夠直接使用Core Foundation的對象,這些對象是toll-free bridging的(一種容許某些OC類與其對應的CoreFoundation類之間能夠互換使用的機制),因此無需進行特殊的對象類型轉換。另外Core Text構建於Core Graphics框架之上,因此能夠經過Core Graphics的方法進行高效高質量的文字描畫。
接下來是Core Text的一些Base Objects。
1.Layout Objects:Framesetters, Frames, Typesetters, Lines and Glyph runs
仍是先上個圖吧:
其中framesetter經過attributed string對象持有文本的內容,並調用typesetter來建立line對象從而填滿由CGPath所描述的區域。輸出的結果是包含了一系列行對象的一個frame。
其中每個line中對於相同屬性內的一段文字使用同一個的CTRun對象去描畫該段文字:
下面這張圖(來自raywenderlich)更加容易理解:
其中CTRun對象會由Core Text自動生成,不須要也不該該由開發者本身去建立,因此整個程序跑起來有不少細節是開發者不用考慮的。
2.Font Objects:Fonts, Font Descriptors, Font Collections
Font Descriptor用來描述字體的特性,是Font的核心部分,Font Collections是許多個Font Descriptors的集合。
說完一大堆Core Text的基本對象後,仍是寫個Demo看看(主要參考了http://blog.csdn.net/andypan1314/article/details/7614469)
首先要使用Core Text框架的話,第一步是要導入CoreText.framework,而後在要使用的頭文件中導入:
#import <CoreText/CoreText.h>
在使用Core Text來draw文字的時候,關鍵是要使用UIView中的drawRect:方法,因此先新建一個ViewController,而後新建一個UIView的子類,並將兩者在視圖上關聯起來。
而後重寫View中的drawRect:方法:
- (void)drawRect:(CGRect)rect { [super drawRect:rect]; // 1.建立一個字符串用來保存文本內容 CFAttributedString NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"First Core Text Demo"]; // 2.建立一個framesetter用來管理描畫文字的frame CTFramesetter CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString); // 3.建立一個用來描畫文字的路徑,其區域爲當前視圖的bounds CGPath CGMutablePathRef path = CGPathCreateMutable(); CGRect rectForPath = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height - 20.0); CGPathAddRect(path, NULL, rectForPath); // 4.建立由framesetter管理的frame,是描畫文字的一個視圖範圍 CTFrame CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attrString.length), path, NULL); // 5.獲取當前視圖的上下文環境 CGContextRef context = UIGraphicsGetCurrentContext(); // 6.經過context在frame中描畫文字內容 CTFrameDraw(frame, context); // 7.全部建立的對象必須被release CFRelease(frame); CFRelease(path); CFRelease(frameSetter); }
以上代碼中各個對象的建立順序基本與Figure 1.3相同。
其中首先對NSAttributedString強制類型轉換獲得CFAtttributedString對象用來保存文本內容,而後建立一個CTFramesetter對象用來保存文本內容、在所管理的Frame中對文字進行佈局、輸出文字等,接着建立CGPath對象和CTFrame對象,兩者定義了一個輸出文字內容的區域。注意CTTypesetter在CTFramesetter建立時隨之而生成了,不須要再手動去建立。
在基本對象建立好後,獲取當前視圖上下文並設置好一些仿射變換後,直接在Frame中draw就完成了文字的輸出:
注意最後全部建立的Core Foundation對象都必須被釋放。
還有一個大問題,draw出來的文字是倒過來的,必需要將它們倒回來。
這就涉及到仿射變換的內容了,有篇文章挺好理解的:http://hi.baidu.com/cqhg1981/item/1a527bf4bda2fb0fc6dc45aa
主要的仿射變換有下面幾種:
其中translation是平移,flip是翻轉,rotation是旋轉,scaling是縮放,shear是錯切,identity是保持不變。
再看看基本的仿射變換代碼:
// 平移仿射變換:tx爲x正方向上的位移量,ty爲y正方向上的位移量 CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty) // 縮放仿射變換:在原點的基礎上進行縮放,sx爲x正方向上的縮放倍數,sy爲y正方向上的縮放倍數。若是縮放倍數爲負數則爲反向縮放 CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy); // 旋轉仿射變換:angle爲旋轉角度,逆時針爲正,順時針爲負 CGContextRotateCTM(CGContextRef c, CGFloat angle);
在CGContextRef context =UIGraphicsGetCurrentContext();下面加上如下代碼。
首先設置好初始的仿射變換矩陣(原封不動):
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
而後將整個視圖向右移動10.0,向下方移動整個視圖的高度:
CGContextTranslateCTM(context, 10.0, self.bounds.size.height);
最後倒過來(方向放大):
CGContextScaleCTM(context, 1.0, -1.0);
Run一下:
完成了。
Core Text還有不少內容,隨着我學習的深刻會繼續更新博客的。