ibireme神的源碼, CoreText 排版,文字排版的專有名詞
CoreText 框架中最常用的幾個類:
下面是該框架的結構圖
CTFrame 作為一個整體的畫布(Canvas),其中由行(CTLine)組成,
而每行CTLine可以分為一個或多個小方塊(CTRun)。
注意:你不需要自己創建CTRun,Core Text將根據NSAttributedString的屬性來自動創建CTRun。
每個CTRun對象對應不同的屬性,正因此,你可以自由的控制字體、顏色、字間距等等信息。
通常處理步聚: 1.使用core text就是先有一個要顯示的string,然後定義這個string每個部分的樣式->attributedString ->生成 CTFramesetter-> 得到CTFrame -> 繪制(CTFrameDraw)
其中???可以更詳細的設置換行方式,對齊方式,繪制區域的大小等???
2.繪制只是顯示,點擊事件就需要一個判斷了。
CTFrame 包含了多個CTLine,並且可以得到各個line的起始位置與大小。判斷點擊處在不在某個line上。
CTLine 又可以判斷這個點(相對於CTLine的坐標)處的文字范圍。然後遍歷這個string的所有NSTextCheckingResult,根據result的rang判斷點擊處在不在這個rang上,從而得到點擊的鏈接與位置。
字體(Font):是一系列字號、樣式和磅值相同的字符(例如:10磅黑體Palatino)。現多被視為字樣的同義詞
字面(Face):是所有字號的磅值和格式的綜合???
字體集(Font family):是一組相關字體(例如:Franklin family包括Franklin Gothic、Fran-klinHeavy和Franklin Compressed)
磅值(Weight):用於描述字體粗度。典型的磅值,從最粗到最細,有極細、細、book、中等、半粗、粗、較粗、極粗
樣式(Style):字形有三種形式:
Roman type是直體;
obliquetype是斜體;
utakuc type是斜體兼曲線(比Roman type更像書法體)???
x高度(X height):指小寫字母的平均高度(以x為基准)。磅值相同的兩字母,x高度越大的字母看起來比x高度小的字母要大
Cap高度(Cap height):與x高度相似。指大寫字母的平均高度(以C為基准)
下行字母(Descender):例如在字母q中,基線以下的字母部分叫下伸部分
上行字母(Ascender):x高度以上的部分(比如字母b)叫做上伸部分
基線(Baseline):通常在x、v、b、m下的那條線 描邊(Stroke):組成字符的線或曲線。可以加粗或改變字符形狀
襯線(Serif):用來使字符更可視的一條水平線。如字母左上角和下部的水平線。
無襯線(Sans Serif):可以讓排字員不使用襯線裝飾。
方形字(Block):這種字體的筆畫使字符看起來比無襯線字更顯眼,但還不到常見的襯線字的程度。例如Lubalin Graph就是方形字,這種字看起來好像是木頭塊刻的一樣
手寫體腳本(Calligraphic script):是一種仿效手寫體的字體。例如Murray Hill或者Fraktur字體
藝術字(Decorative):像繪畫般的字體
Pi符號(Pisymbol):非標准的字母數字字符的特殊符號。例如Wingdings和Mathematical Pi
連寫(Ligature):是一系列連寫字母如fi、fl、ffi或ffl。由於字些字母形狀的原因經常被連寫,故排字員已習慣將它們連寫。
讀完了上面這些概念,可以參考一下下面的圖片,看看具體的位置
其中,在 Apple 的 SDK 中是這樣定義這些屬性的
const CFStringRef kCTCharacterShapeAttributeName;
//字體形狀屬性 必須是CFNumberRef對象默認為0,非0則對應相應的字符形狀定義,如1表示傳統字符形狀
const CFStringRef kCTFontAttributeName;
//字體屬性 必須是CTFont對象
const CFStringRef kCTKernAttributeName;
//字符間隔屬性 必須是CFNumberRef對象
const CFStringRef kCTLigatureAttributeName;
//設置是否使用連字屬性,設置為0,表示不使用連字屬性。標准的英文連字有FI,FL.默認值為1,既是使用標准連字。也就是當搜索到f時候,會把fl當成一個文字。必須是CFNumberRef 默認為1,可取0,1,2
const CFStringRef kCTForegroundColorAttributeName;
//字體顏色屬性 必須是CGColor對象,默認為black
const CFStringRef kCTForegroundColorFromContextAttributeName;
//上下文的字體顏色屬性 必須為CFBooleanRef 默認為False
const CFStringRef kCTParagraphStyleAttributeName;
//段落樣式屬性 必須是CTParagraphStyle對象 默認為NIL
const CFStringRef kCTStrokeWidthAttributeName;
//筆畫線條寬度 必須是CFNumberRef對象,默為0.0f,標准為3.0f
const CFStringRef kCTStrokeColorAttributeName;
//筆畫的顏色屬性 必須是CGColorRef 對象,默認為前景色
const CFStringRef kCTSuperscriptAttributeName;
//設置字體的上下標屬性 必須是CFNumberRef對象 默認為0,可為-1為下標,1為上標,需要字體支持才行。如排列組合的樣式Cn1
const CFStringRef kCTUnderlineColorAttributeName;
//字體下劃線顏色屬性 必須是CGColorRef對象,默認為前景色
const CFStringRef kCTUnderlineStyleAttributeName;
//字體下劃線樣式屬性 必須是CFNumberRef對象,默為kCTUnderlineStyleNone 可以通過CTUnderlineStyleModifiers 進行修改下劃線風格
const CFStringRef kCTVerticalFormsAttributeName;
//文字的字形方向屬性 必須是CFBooleanRef 默認為false,false表示水平方向,true表示豎直方向
const CFStringRef kCTGlyphInfoAttributeName;
//字體信息屬性 必須是CTGlyphInfo對象
const CFStringRef kCTRunDelegateAttributeName
//CTRun 委托屬性 必須是CTRunDelegate對象
const CFStringRef kCTCharacterShapeAttributeName;
//字體形狀屬性 必須是CFNumberRef對象默認為0,非0則對應相應的字符形狀定義,如1表示傳統字符形狀
const CFStringRef kCTFontAttributeName;
//字體屬性 必須是CTFont對象
const CFStringRef kCTKernAttributeName;
//字符間隔屬性 必須是CFNumberRef對象
const CFStringRef kCTLigatureAttributeName;
//設置是否使用連字屬性,設置為0,表示不使用連字屬性。標准的英文連字有FI,FL.默認值為1,既是使用標准連字。也就是當搜索到f時候,會把fl當成一個文字。必須是CFNumberRef 默認為1,可取0,1,2
const CFStringRef kCTForegroundColorAttributeName;
//字體顏色屬性 必須是CGColor對象,默認為black
const CFStringRef kCTForegroundColorFromContextAttributeName;
//上下文的字體顏色屬性 必須為CFBooleanRef 默認為False
const CFStringRef kCTParagraphStyleAttributeName;
//段落樣式屬性 必須是CTParagraphStyle對象 默認為NIL
const CFStringRef kCTStrokeWidthAttributeName;
//筆畫線條寬度 必須是CFNumberRef對象,默為0.0f,標准為3.0f
const CFStringRef kCTStrokeColorAttributeName;
//筆畫的顏色屬性 必須是CGColorRef 對象,默認為前景色
const CFStringRef kCTSuperscriptAttributeName;
//設置字體的上下標屬性 必須是CFNumberRef對象 默認為0,可為-1為下標,1為上標,需要字體支持才行。如排列組合的樣式Cn1
const CFStringRef kCTUnderlineColorAttributeName;
//字體下劃線顏色屬性 必須是CGColorRef對象,默認為前景色
const CFStringRef kCTUnderlineStyleAttributeName;
//字體下劃線樣式屬性 必須是CFNumberRef對象,默為kCTUnderlineStyleNone 可以通過CTUnderlineStypleModifiers 進行修改下劃線風格
const CFStringRef kCTVerticalFormsAttributeName;
//文字的字形方向屬性 必須是CFBooleanRef 默認為false,false表示水平方向,true表示豎直方向
const CFStringRef kCTGlyphInfoAttributeName;
//字體信息屬性 必須是CTGlyphInfo對象
const CFStringRef kCTRunDelegateAttributeName
//CTRun 委托屬性 必須是CTRunDelegate對象
例如:
NSMutableAttributedString *mabstring =
[[NSMutableAttributedString alloc]initWithString:
@"This is a test of characterAttribute. 中文字符"];
//設置字體屬性 CTFontRef font =
CTFontCreateWithName(CFSTR("Georgia"), 40, NULL);
[mabstring addAttribute:(id)kCTFontAttributeName
value:(id)font range:NSMakeRange(0, 4)];
//設置斜體字 CTFontRef font =
CTFontCreateWithName((CFStringRef)[UIFont italicSystemFontOfSize:20].fontName,
14, NULL);
[mabstring addAttribute:(id)kCTFontAttributeName
value:(id)font range:NSMakeRange(0, 4)];
kCTUnderlineStyleAttributeName
kCTUnderlineStyleDouble
//下劃線 [mabstring addAttribute:(id)kCTUnderlineStyleAttributeName
value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble]
range:NSMakeRange(0, 4)];
//下劃線顏色 [mabstring addAttribute:(id)kCTUnderlineColorAttributeName
value:(id)[UIColor redColor].CGColor range:NSMakeRange(0, 4)];
//設置字體簡隔 eg:test long number = 10;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTKernAttributeName
value:(id)num range:NSMakeRange(10, 4)];
//設置連字
long number = 1;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTLigatureAttributeName
value:(id)num range:NSMakeRange(0, [str length])];
暫時沒有效果圖
//設置字體顏色
[mabstring addAttribute:(id)kCTForegroundColorAttributeName
value:(id)[UIColor redColor].CGColor range:NSMakeRange(0, 9)];
//設置字體顏色為前影色 CFBooleanRef flag = kCFBooleanTrue;
[mabstring addAttribute:(id)kCTForegroundColorFromContextAttributeName
value:(id)flag range:NSMakeRange(5, 10)];
暫無效果。。
//設置空心字
long number = 2;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTStrokeWidthAttributeName
value:(id)num range:NSMakeRange(0, [str length])];
//設置空心字
long number = 2; CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTStrokeWidthAttributeName
value:(id)num range:NSMakeRange(0, [str length])]; //設置空心字顏色
[mabstring addAttribute:(id)kCTStrokeColorAttributeName
value:(id)[UIColor greenColor].CGColor
range:NSMakeRange(0, [str length])];
在設置空心字顏色時,必須先將字體高為空心,否則設置顏色是沒有效果的。
//對同一段字體進行多屬性設置
//紅色
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)[UIColor redColor].CGColor forKey:(id)kCTForegroundColorAttributeName];
//斜體
CTFontRef font = CTFontCreateWithName((CFStringRef)[UIFont italicSystemFontOfSize:20].fontName, 40, NULL);
[attributes setObject:(id)font forKey:(id)kCTFontAttributeName];
//下劃線
[attributes setObject:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble] forKey:(id)kCTUnderlineStyleAttributeName];
[mabstring addAttributes:attributes range:NSMakeRange(0, 4)];
最後 Draw 一下
-(void)characterAttribute
{
NSString *str = @"This is a test of characterAttribute. 中文字符";
NSMutableAttributedString *mabstring = [[NSMutableAttributedString alloc]initWithString:str];
[mabstring beginEditing];
/*
long number = 1;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTCharacterShapeAttributeName value:(id)num range:NSMakeRange(0, 4)];
*/
/*
//設置字體屬性
CTFontRef font = CTFontCreateWithName(CFSTR("Georgia"), 40, NULL);
[mabstring addAttribute:(id)kCTFontAttributeName value:(id)font range:NSMakeRange(0, 4)];
*/
/*
//設置字體簡隔 eg:test
long number = 10;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTKernAttributeName value:(id)num range:NSMakeRange(10, 4)];
*/
/*
long number = 1;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTLigatureAttributeName value:(id)num range:NSMakeRange(0, [str length])];
*/
/*
//設置字體顏色
[mabstring addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor redColor].CGColor range:NSMakeRange(0, 9)];
*/
/*
//設置字體顏色為前影色
CFBooleanRef flag = kCFBooleanTrue;
[mabstring addAttribute:(id)kCTForegroundColorFromContextAttributeName value:(id)flag range:NSMakeRange(5, 10)];
*/
/*
//設置空心字
long number = 2;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTStrokeWidthAttributeName value:(id)num range:NSMakeRange(0, [str length])];
//設置空心字顏色
[mabstring addAttribute:(id)kCTStrokeColorAttributeName value:(id)[UIColor greenColor].CGColor range:NSMakeRange(0, [str length])];
*/
/*
long number = 1;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);
[mabstring addAttribute:(id)kCTSuperscriptAttributeName value:(id)num range:NSMakeRange(3, 1)];
*/
/*
//設置斜體字
CTFontRef font = CTFontCreateWithName((CFStringRef)[UIFont italicSystemFontOfSize:20].fontName, 14, NULL);
[mabstring addAttribute:(id)kCTFontAttributeName value:(id)font range:NSMakeRange(0, 4)];
*/
/*
//下劃線
[mabstring addAttribute:(id)kCTUnderlineStyleAttributeName value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble] range:NSMakeRange(0, 4)];
//下劃線顏色
[mabstring addAttribute:(id)kCTUnderlineColorAttributeName value:(id)[UIColor redColor].CGColor range:NSMakeRange(0, 4)];
*/
//對同一段字體進行多屬性設置
//紅色
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)[UIColor redColor].CGColor forKey:(id)kCTForegroundColorAttributeName];
//斜體
CTFontRef font = CTFontCreateWithName((CFStringRef)[UIFont italicSystemFontOfSize:20].fontName, 40, NULL);
[attributes setObject:(id)font forKey:(id)kCTFontAttributeName];
//下劃線
[attributes setObject:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble] forKey:(id)kCTUnderlineStyleAttributeName];
[mabstring addAttributes:attributes range:NSMakeRange(0, 4)];
NSRange kk = NSMakeRange(0, 4);
NSDictionary * dc = [mabstring attributesAtIndex:0 effectiveRange:&kk];
[mabstring endEditing];
NSLog(@"value = %@",dc);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mabstring);
CGMutablePathRef Path = CGPathCreateMutable();
CGPathAddRect(Path, NULL ,CGRectMake(10 , 0 ,self.bounds.size.width-10 , self.bounds.size.height-10));
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), Path, NULL);
//獲取當前(View)上下文以便於之後的繪畫,這個是一個離屏。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context , CGAffineTransformIdentity);
//壓棧,壓入圖形狀態棧中.每個圖形上下文維護一個圖形狀態棧,並不是所有的當前繪畫環境的圖形狀態的元素都被保存。圖形狀態中不考慮當前路徑,所以不保存
//保存現在得上下文圖形狀態。不管後續對context上繪制什麼都不會影響真正得屏幕。
CGContextSaveGState(context);
//x,y軸方向移動
CGContextTranslateCTM(context , 0 ,self.bounds.size.height);
//縮放x,y軸方向縮放,-1.0為反向1.0倍,坐標系轉換,沿x軸翻轉180度
CGContextScaleCTM(context, 1.0 ,-1.0);
CTFrameDraw(frame,context);
CGPathRelease(Path);
CFRelease(framesetter);
}
- (void)drawRect:(CGRect)rect
{
[self characterAttribute];
}
這個是前言
學習CoreText,寫一個雜志類的應用,如網易和zarca應用
1、對CGContextRef的CTM理解。
2、對NS的了解,文字繪制方面的座標系。
3、對CoreText的API。
CTM,Context Translate Matrix。 它是把要繪制的上下文以一個叫做Matrix的東西來表示,可以簡單地想作,繪制的上下文的每一個點都映射在Matrix上,你在Matrix上的操作都會使得上下文上的點產生相應的變動。如放大、旋轉、移動。
為了達到旋轉或放大縮小的目的,一般都會先改變這個上下文,如:
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
// some draw code
// ....
然後進行繪圖操作。那麼這個繪圖操作是怎麼做的呢?這個對Matrix的操作,為什麼是放在前面而不是放在後面,先從context來了解。
一般情況也,我們誤認為context就是畫布,所有的matrix旋轉都是針對畫布的旋轉,但是這樣的理解是錯誤的,雖然得到的結果是正確的
其實context說的是繪畫人所處的角度上下文。如下圖,默認的情況下,繪畫人的角度是正對著畫布的:
畫布是白色的,在左上角用一個黃色的三角形來標識它的左上角,使用left top來標識context的左上角,而繪畫人是黃色的圓形。
要記著!!畫布無論怎麼樣都是正對著屏幕的,它不會旋轉,或者放大縮小,或者移動。
那麼為什麼又看起來放大了或者移動了呢?其實移動的是你的context,也就是你所處的context視角,我舉個例子,比方說我要旋轉180度在左上角寫一個“abcdefg”。
首先,我要先旋轉180度:
然後,我在左上角寫上“abcdefg”:
然後重置context:
可以看到,我們改變context只是改變了自己面對畫布的角度,而畫布仍然是正對著屏幕的,剛才繪畫abcdefg時的座標(0,0)是你旋轉後context的left top,而不是畫布 的左上角,記著這一點很重要。(因為旋轉了context180度,實際上座標0,0是畫布的右下角了,始終記住畫布它從來就沒動過,畫布始終是正對著屏幕的)
所以,在繪畫的時候,其實是倒著畫在了畫布的右下角上。而重置context,則是把自己正對著畫布而已。這也就說清了為什麼是在使用matrix更改context之後進行繪圖有效(把自己面對畫布的角度先調整了),而不是在畫了之後再調整(因為你都畫完了,再調整自己的角度還有什麼用?)。
正確理解使用matrix更改context的方式很重要,因為這涉及到坐標系的問題,之後的CoreText相當討論會講到一個例子。
NS坐標系是以左下角為(0,0),所以NS坐標系是與iOS的UIKit坐標系在Y上是相反的,所以,在iOS進行CoreText進行繪圖或文字的時候,X方向是一致的,但是Y則是倒過來的。當你在(20, 20)的坐標處用CoreText畫一個長方形,其實就是畫布的(20, canvas.height - 20 + rect.size.height)的位置上畫了個長方形,而且是倒過來的。如下圖:
那麼怎麼辦呢?想想,仔細看上面這張圖,貌似像是正常方向的倒影,但是水平線卻在最上面。嗯,挪下來,然後再反過來,看一下效果。如下圖:
效果:
效果果然如圖所示,好!!
可是是不是就這樣完了呢?不是,還有一個更為重要的問題,這個時候,進行了兩次的轉換matrix,context的left top在哪裡呢?
根據之前的理論,那得讓自己先把自己向下移,然後把頭倒過來,OK,這下明白了,這下畫布的左下角變成了context的左上角,別的都沒變。這時,當你在(20, 20)的坐標處用CoreText畫一個長方形,其實就是畫布的(20, canvas.height - 20 + rect.size.height)的位置上畫了個長方形,而且是倒過來的。
仔細想想這個,有趣的事情還有很多,因為按照自己看過本文之前的理論,可能會非常驚訝為什麼得到的結果和自己想的不一樣,一直以為是在(20, 20)處畫一個長方形,結果卻剛好相反,這就是沒有理解context及matrix的正確含義所致。
使用Create函數建立的對象引用,必須要使用CFRelease掉。
這是一個低級的API,它的數據源是NSAttributedString。它可以根據NSAttributedString的定義的每個range的subNSAttributedString的樣式進行對字符串的渲染。可以這樣說,這是一個富文本渲染器。
UIWebView做不了一些東西,比如說分列顯示,這點webpage難以做到
那麼為什麼要用CoreText呢?其實很重要的一點是那個無用的UILabel控件,尤其是多行文本時,它竟然只能垂直居中。
另,使用CoreText可以很好地做一些個性化的東西,比如可以使用動畫,這一點UIWebView做不到。它能做一些很cool的東西,比方說,雜志,新聞類的應用。
CTFramesetterRef
按名字就知道,這是一個setter,一個屬性設置器,它引用了一些有用的對像,諸如字體之類的,它的工作就是,生成一個CTFrameRef對象。
CTFrameRef
這是一個Frame對象,用於表示一個繪制區域,它是由CTFramesetterRef生成。
CTLineRef
表示要繪制的一行。CTFrameRef對象包含了多個line對象。
CTNodeRef
表示要繪制的某個節點(subNSAttributedString),每line對象包含多個node對象,這個節點表示著不同格式的NSAttributedString對象的如何繪制。在中間插入圖片的話,這個就要考慮了。CoreText是不支持中間插入圖片的,不過我們可以在讀到特殊標記的node的時候,返回不同的行高和行寬,預留空間,在繪制完coretext之後,在這些個空間處繪制相應的圖片。
其實流程是這樣的:
1、生成要繪制的NSAttributedString對象。
2、生成一個CTFramesetterRef對象,然後創建一個CGPath對象,這個Path對象用於表示可繪制區域坐標值、長寬。
3、使用上面生成的setter和path生成一個CTFrameRef對象,這個對象包含了這兩個對象的信息(字體信息、坐標信息),它就可以使用CTFrameDraw方法繪制了。
這裡有一個demo代碼:
- (void)_drawRectWithContext:(CGContextRef)context { // generate NSAttributedString object NSAttributedString *contentAttrString = [self _generateAttributeString]; // 初始一個 path CGRect bounds = CGRectInset(self.bounds, 10.0f, 10.0f); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, bounds); // ------------------------ begin draw // 初始一個framesetter CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(contentAttrString));
// 通過 framesetter 和 path 生成 Frame CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); CTFrameDraw(frame, context); CFRelease(frame); CFRelease(path); CFRelease(framesetter); // ------------------------ end draw }
一直都在說CoreText的事情,那麼怎麼使用NSAttributedString呢?怎麼設置NSAttributedString的屬性,怎麼設計行高,怎麼設置字體大小,樣式?
首先得會設置屬性,調用NSAttributedString的setAttributes:range:
方法就可以設置屬性:
// set attributes to attributed string
[attrString setAttributes:attributes
range:NSMakeRange(0, attrString.length)];
那麼都有哪些屬性呢?有下面這些屬性:
const CFStringRef kCTCharacterShapeAttributeName;
const CFStringRef kCTFontAttributeName;
const CFStringRef kCTKernAttributeName;
const CFStringRef kCTLigatureAttributeName;
const CFStringRef kCTForegroundColorAttributeName;
const CFStringRef kCTForegroundColorFromContextAttributeName;
const CFStringRef kCTParagraphStyleAttributeName;
const CFStringRef kCTStrokeWidthAttributeName;
const CFStringRef kCTStrokeColorAttributeName;
const CFStringRef kCTSuperscriptAttributeName;
const CFStringRef kCTUnderlineColorAttributeName;
const CFStringRef kCTUnderlineStyleAttributeName;
const CFStringRef kCTVerticalFormsAttributeName;
const CFStringRef kCTGlyphInfoAttributeName;
const CFStringRef kCTRunDelegateAttributeName
下面是說明:
kCTCharacterShapeAttributeName
Controls glyph selection. Value must be a CFNumberRef object. Default is value is 0 (disabled). A non-zero value is interpreted as Apple Type Services kCharacterShapeType selector + 1 (see for selectors). For example, an attribute value of 1 corresponds to kTraditionalCharactersSelector.
kCTFontAttributeName
The font of the text to which this attribute applies. The value associated with this attribute must be a CTFont object. Default is Helvetica 12.
kCTKernAttributeName
The amount to kern the next character. The value associated with this attribute must be a CFNumber float. Default is standard kerning. The kerning attribute indicates how many points the following character should be shifted from its default offset as defined by the current character’s font in points: a positive kern indicates a shift farther away from and a negative kern indicates a shift closer to the current character. If this attribute is not present, standard kerning is used. If this attribute is set to 0.0, no kerning is done at all.
kCTLigatureAttributeName
The type of ligatures to use. The value associated with this attribute must be a CFNumber object. Default is an integer value of 1. The ligature attribute determines what kinds of ligatures should be used when displaying the string. A value of 0 indicates that only ligatures essential for proper rendering of text should be used. A value of 1 indicates that standard ligatures should be used, and 2 indicates that all available ligatures should be used. Which ligatures are standard depends on the script and possibly the font. Arabic text, for example, requires ligatures for many character sequences but has a rich set of additional ligatures that combine characters. English text has no essential ligatures, and typically has only two standard ligatures, those for “fi” and “fl”—all others are considered more advanced or fancy.
kCTForegroundColorAttributeName
The foreground color of the text to which this attribute applies. The value associated with this attribute must be a CGColor object. Default value is black.
kCTForegroundColorFromContextAttributeName
Sets a foreground color using the context’s fill color. Value must be a CFBooleanRef object. Default is false. The reason this exists is because an NSAttributedString object defaults to a black color if no color attribute is set. This forces Core Text to set the color in the context. This attribute allows developers to sidestep this, making Core Text set nothing but font information in the CGContext. If set, this attribute also determines the color used by kCTUnderlineStyleAttributeName, in which case it overrides the foreground color.
kCTParagraphStyleAttributeName
The paragraph style of the text to which this attribute applies. A paragraph style object is used to specify things like line alignment, tab rulers, writing direction, and so on. Value must be aCTParagraphStyle
object. Default is an empty CTParagraphStyle object. See CTParagraphStyle Reference for more information.
kCTStrokeWidthAttributeName
The stroke width. Value must be a CFNumberRef object. Default value is 0.0, or no stroke. This attribute, interpreted as a percentage of font point size, controls the text drawing mode: positive values effect drawing with stroke only; negative values are for stroke and fill. A typical value for outlined text is 3.0.
kCTStrokeColorAttributeName
The stroke color. Value must be a CGColorRef object. Default is the foreground color.
kCTSuperscriptAttributeName
Controls vertical text positioning. Value must be a CFNumberRef object. Default is integer value 0. If supported by the specified font, a value of 1 enables superscripting and a value of -1 enables subscripting.
kCTUnderlineColorAttributeName
The underline color. Value must be a CGColorRef object. Default is the foreground color.
kCTUnderlineStyleAttributeName
The style of underlining, to be applied at render time, for the text to which this attribute applies. Value must be a CFNumber object. Default is kCTUnderlineStyleNone. Set a value of something other than kCTUnderlineStyleNone to draw an underline. In addition, the constants listed in “CTUnderlineStyleModifiers” can be used to modify the look of the underline. The underline color is determined by the text’s foreground color.
kCTVerticalFormsAttributeName
The orientation of the glyphs in the text to which this attribute applies. Value must be a CFBoolean object. Default is False. A value of False indicates that horizontal glyph forms are to be used; True indicates that vertical glyph forms are to be used.
kCTGlyphInfoAttributeName
The glyph info object to apply to the text associated with this attribute. Value must be a CTGlyphInfo object. The glyph specified by this CTGlyphInfo object is assigned to the entire attribute range, provided that its contents match the specified base string and that the specified glyph is available in the font specified by kCTFontAttributeName. See CTGlyphInfo Reference for more information.
kCTRunDelegateAttributeName
The run-delegate object to apply to an attribute range of the string. The value must be a CTRunDelegate object. The run delegate controls such typographic traits as glyph ascent, descent, and width. The values returned by the embedded run delegate apply to each glyph resulting from the text in that range. Because an embedded object is only a display-time modification, you should avoid applying this attribute to a range of text with complex behavior, such as text having a change of writing direction or having combining marks. It is thus recommended you apply this attribute to a range containing the single character U+FFFC. See CTRunDelegate Reference for more information.
上面所述的東西貌似只是說明了設置字體與樣式,卻沒有行高、縮進之類的東西哦!!
嗯,不是沒有,而是CoreText把它當成是段落樣式來設置了,也就是說,要設置kCTParagraphStyleAttributeName
的屬性就行。kCTParagraphStyleAttributeName
屬性的值是一個CTParagraphStyle
對象,你需要把你想要設置的段落屬性放進這個對象就可以設置行高之類的東西:
kCTParagraphStyleSpecifierAlignment = 0,
kCTParagraphStyleSpecifierFirstLineHeadIndent = 1,
kCTParagraphStyleSpecifierHeadIndent = 2,
kCTParagraphStyleSpecifierTailIndent = 3,
kCTParagraphStyleSpecifierTabStops = 4,
kCTParagraphStyleSpecifierDefaultTabInterval = 5,
kCTParagraphStyleSpecifierLineBreakMode = 6,
kCTParagraphStyleSpecifierLineHeightMultiple = 7,
kCTParagraphStyleSpecifierMaximumLineHeight = 8,
kCTParagraphStyleSpecifierMinimumLineHeight = 9,
kCTParagraphStyleSpecifierLineSpacing = 10, /* deprecated */
kCTParagraphStyleSpecifierParagraphSpacing = 11,
kCTParagraphStyleSpecifierParagraphSpacingBefore = 12,
kCTParagraphStyleSpecifierBaseWritingDirection = 13,
kCTParagraphStyleSpecifierMaximumLineSpacing = 14,
kCTParagraphStyleSpecifierMinimumLineSpacing = 15,
kCTParagraphStyleSpecifierLineSpacingAdjustment = 16,
kCTParagraphStyleSpecifierLineBoundsOptions = 17,
kCTParagraphStyleSpecifierCount
下面是說明:
kCTParagraphStyleSpecifierAlignment
The text alignment. Natural text alignment is realized as left or right alignment, depending on the line sweep direction of the first script contained in the paragraph. Type: CTTextAlignment. Default: kCTNaturalTextAlignment. Application: CTFramesetter.
kCTParagraphStyleSpecifierFirstLineHeadIndent
The distance, in points, from the leading margin of a frame to the beginning of the paragraph’s first line. This value is always nonnegative. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierHeadIndent
The distance, in points, from the leading margin of a text container to the beginning of lines other than the first. This value is always nonnegative. Type: CGFloat Default: 0.0 Application: CTFramesetter
kCTParagraphStyleSpecifierTailIndent
The distance, in points, from the margin of a frame to the end of lines. If positive, this value is the distance from the leading margin (for example, the left margin in left-to-right text). If 0 or negative, it’s the distance from the trailing margin. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierTabStops
The CTTextTab objects, sorted by location, that define the tab stops for the paragraph style. Type: CFArray of CTTextTabRef. Default: 12 left-aligned tabs, spaced by 28.0 points. Application: CTFramesetter, CTTypesetter.
kCTParagraphStyleSpecifierDefaultTabInterval
The documentwide default tab interval. Tabs after the last specified by kCTParagraphStyleSpecifierTabStops are placed at integer multiples of this distance (if positive). Type: CGFloat. Default: 0.0. Application: CTFramesetter, CTTypesetter.
kCTParagraphStyleSpecifierLineBreakMode
The mode that should be used to break lines when laying out the paragraph’s text. Type: CTLineBreakMode. Default: kCTLineBreakByWordWrapping. Application: CTFramesetter
kCTParagraphStyleSpecifierLineHeightMultiple
The line height multiple. The natural line height of the receiver is multiplied by this factor (if positive) before being constrained by minimum and maximum line height. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierMaximumLineHeight
The maximum height that any line in the frame will occupy, regardless of the font size or size of any attached graphic. Glyphs and graphics exceeding this height will overlap neighboring lines. A maximum height of 0 implies no line height limit. This value is always nonnegative. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierMinimumLineHeight
The minimum height that any line in the frame will occupy, regardless of the font size or size of any attached graphic. This value is always nonnegative. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierLineSpacing
The space in points added between lines within the paragraph (commonly known as leading). This value is always nonnegative. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierParagraphSpacing
The space added at the end of the paragraph to separate it from the following paragraph. This value is always nonnegative and is determined by adding the previous paragraph’s kCTParagraphStyleSpecifierParagraphSpacing setting and the current paragraph’s kCTParagraphStyleSpecifierParagraphSpacingBefore setting. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierParagraphSpacingBefore
The distance between the paragraph’s top and the beginning of its text content. Type: CGFloat. Default: 0.0. Application: CTFramesetter.
kCTParagraphStyleSpecifierBaseWritingDirection
The base writing direction of the lines. Type: CTWritingDirection. Default: kCTWritingDirectionNatural. Application: CTFramesetter, CTTypesetter.
kCTParagraphStyleSpecifierCount
The number of style specifiers. The purpose is to simplify validation of style specifiers
那麼怎麼編碼呢?也就是這些屬性怎麼用呢?下面是一個demo:
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:_content];
// line space
CTParagraphStyleSetting lineSpaceSetting;
lineSpaceSetting.spec = kCTParagraphStyleSpecifierLineSpacing;
lineSpaceSetting.value = &_lineSpace;
lineSpaceSetting.valueSize = sizeof(float);
// indent
CTParagraphStyleSetting indentSetting;
indentSetting.spec = kCTParagraphStyleSpecifierFirstLineHeadIndent;
indentSetting.value = &_indent;
indentSetting.valueSize = sizeof(float);
// composite settings
CTParagraphStyleSetting settings[] = {
lineSpaceSetting,
indentSetting
};
CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 2);
// build attributes
NSDictionary *attributes = @{(__bridge id)kCTParagraphStyleAttributeName: (__bridge id)style};
// set attributes to attributed string
[attrString setAttributes:attributes
range:NSMakeRange(0, attrString.length)];
這個東西是相當有趣的東東,可以使用CTFrameGetVisibleStringRange
函數來計算指定frame繪制了多少字符,那麼就可以另建一個frame把剩余的字符繪制進去:
// get current context and store it's state
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
// translate CTM for iOS
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
// generate attributed string
NSAttributedString *attrString = [self _generateAttributedString];
// Draw code start -------------------------------------------------------------------------------------------------
CGRect bounds = CGRectInset(self.bounds, 25.0f, 25.0f);
float columnWidth = (bounds.size.width - 30.0f) / 2.0f;
float columnHeight = bounds.size.height;
CTFramesetterRef framesetter
= CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attrString));
int location = 0;
// ------------- first column
CGRect firstColumnRect = CGRectMake(bounds.origin.x, bounds.origin.y, columnWidth, columnHeight);
CGMutablePathRef firstColumnPath = CGPathCreateMutable();
CGPathAddRect(firstColumnPath, NULL, firstColumnRect);
CTFrameRef firstColumnFrame =
CTFramesetterCreateFrame(framesetter, CFRangeMake(location, 0), firstColumnPath, NULL);
CFRange firstColumnStringRange = CTFrameGetVisibleStringRange(firstColumnFrame);
CTFrameDraw(firstColumnFrame, context);
// recalculate the location for next frame.
location = firstColumnStringRange.length;
// ------------- second column
CGRect secondColumnRect =
CGRectMake(bounds.origin.x + 30 + columnWidth, bounds.origin.y, columnWidth, columnHeight);
CGMutablePathRef secondColumnPath = CGPathCreateMutable();
CGPathAddRect(secondColumnPath, NULL, secondColumnRect);
CTFrameRef secondColumnFrame =
CTFramesetterCreateFrame(framesetter,
CFRangeMake(location, 0),
secondColumnPath, NULL);
CTFrameDraw(secondColumnFrame, context);
// release
CFRelease(firstColumnPath);
CFRelease(firstColumnFrame);
CFRelease(secondColumnPath);
CFRelease(secondColumnFrame);
CFRelease(framesetter);
// Draw code end -------------------------------------------------------------------------------------------------
// restore current context
CGContextRestoreGState(context);