? ? 首先我是萌新,ios開發(fā)新手,一些大牛覺得不對(duì),錯(cuò)誤的,請(qǐng)勿噴我怎么吃螃蟹,請(qǐng)告訴我怎么吃就好了,謝謝了。
? ? 之前因?yàn)轫?xiàng)目需求,要給小說閱讀器中內(nèi)容加上下劃線,但是這個(gè)下劃線又跟其他的不一樣,這個(gè)下劃線要在基線的位置再靠上一些,當(dāng)初不明白為什么要這么做,而且效果也很難看,用戶體驗(yàn)也不好,但是老大說這能防止pdf掃描vip章節(jié)內(nèi)容,所以還是得老老實(shí)實(shí)的做,就對(duì)coreText開始了研究。
本次主要用到的點(diǎn)在與CTLineRef.接下來先對(duì)其做一些了解。
1.字符(Character)和字形(Glyphs)
排版系統(tǒng)中文本顯示的一個(gè)重要的過程就是字符到字形的轉(zhuǎn)換,字符是信息本身的元素,而字形是字符的圖形表征,字符還會(huì)有其它表征比如發(fā)音。 字符在計(jì)算機(jī)中其實(shí)就是一個(gè)編碼,某個(gè)字符集中的編碼,比如Unicode字符集,就囊括了大都數(shù)存在的字符。 而字形則是圖形,一般都存儲(chǔ)在字體文件中,字形也有它的編碼,也就是它在字體中的索引。 一個(gè)字符可以對(duì)應(yīng)多個(gè)字形(不同的字體,或者同種字體的不同樣式:粗體斜體等);多個(gè)字符也可能對(duì)應(yīng)一個(gè)字形,比如字符的連寫( Ligatures)。

下面就來看看字形的各個(gè)參數(shù)也就是所謂的字形度量Glyph Metrics,其實(shí)我認(rèn)為就是一個(gè)小時(shí)侯學(xué)寫字母的時(shí)候的作業(yè)本一樣的各個(gè)線

bounding box(邊界框 bbox),這是一個(gè)假想的框子,它盡可能緊密的裝入字形。
baseline(基線),一條假想的線,一行上的字形都以此線作為上下位置的參考,在這條線的左側(cè)存在一個(gè)點(diǎn)叫做基線的原點(diǎn),
ascent(上行高度)從原點(diǎn)到字體中最高(這里的高深都是以基線為參照線的)的字形的頂部的距離,ascent是一個(gè)正值
descent(下行高度)從原點(diǎn)到字體中最深的字形底部的距離,descent是一個(gè)負(fù)值(比如一個(gè)字體原點(diǎn)到最深的字形的底部的距離為2,那么descent就為-2)
linegap(行距),linegap也可以稱作leading(其實(shí)準(zhǔn)確點(diǎn)講應(yīng)該叫做External leading),行高lineHeight則可以通過 ascent + |descent| + linegap 來計(jì)算。
一些Metrics專業(yè)知識(shí)還可以參考Free Type的文檔 Glyph metrics,其實(shí)iOS就是使用Free Type庫來進(jìn)行字體渲染的。
以上圖片和部分概念來自蘋果文檔 Querying Font Metrics ,Text Layout
2.坐標(biāo)系
蘋果編程中的坐標(biāo)系不明白為什么會(huì)各有不同。 傳統(tǒng)的Mac中的坐標(biāo)系的原點(diǎn)在左下角,比如NSView默認(rèn)的坐標(biāo)系,原點(diǎn)就在左下角。但Mac中有些View為了其實(shí)現(xiàn)的便捷將原點(diǎn)變換到左上角,像NSTableView的坐標(biāo)系坐標(biāo)原點(diǎn)就在左上角。iOS UIKit的UIView的坐標(biāo)系原點(diǎn)在左上角。
看完上邊兒這些,該上代碼勒。
先拿一個(gè)定義好的屬性字符串。
NSMutableAttributedString *attrString = [[NSMutableAttributedString? alloc] initWithString:self.text];//這個(gè)self.text 就是你要用到的字符串
[attrString setAttributes:self.coreTextAttributes range:NSMakeRange(0, attrString.length)];//這里的self.coreTextAttributes就是一個(gè)字典,來配置這個(gè)屬性字符串的,可在他的set方法中隨意設(shè)置,比如顏色,下劃線,刪除線,字型等等
然后把屬性字符串放到frame中
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) attrString);
CGPathRef path = CGPathCreateWithRect(self.bounds, NULL);
if (_ctFrame != NULL) { ?//這里的_ctFrame 就是一個(gè)裝有字符屬性的集合
CFRelease(_ctFrame), _ctFrame = NULL;
}
_ctFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
CFRelease(path);
CFRelease(frameSetter);
做完了上面這些,就該開始畫字了。
在- (void)drawRect:(CGRect)rect方法中
if (!_ctFrame) return;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CTFrameDraw(_ctFrame, context);
這樣寫的效果如圖

是鏡像過來的,要再翻過來
CGAffineTransform transform = CGAffineTransformMake(1,0,0,-1,0,self.bounds.size.height);
CGContextConcatCTM(context, transform);
加上以上這兩句就可以了,就順利的將字畫到了畫布上。
再之后給文字加個(gè)方框
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));
CFArrayRef lines = CTFrameGetLines(_ctFrame);
CFIndex linecount = CFArrayGetCount(lines);
CGPoint origins[linecount];
CTFrameGetLineOrigins(_ctFrame, CFRangeMake(0, 0), origins);
NSInteger lineIndex = 0;
for (id oneLine in (__bridge NSArray *)lines) {
CGRect lineBounds = CTLineGetImageBounds((CTLineRef)oneLine, context);
lineBounds.origin.x += origins[lineIndex].x;
lineBounds.origin.y += origins[lineIndex].y;
lineIndex ++;
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, 1.0);
CGPoint poins[] = {CGPointMake(lineBounds.origin.x, lineBounds.origin.y),CGPointMake(lineBounds.origin.x+lineBounds.size.width, lineBounds.origin.y),CGPointMake(lineBounds.origin.x+lineBounds.size.width, lineBounds.origin.y+lineBounds.size.height),CGPointMake(lineBounds.origin.x, lineBounds.origin.y+lineBounds.size.height)};//繪制四邊,位置隨意調(diào)整,位置可以調(diào)整之后也就可以實(shí)現(xiàn)我的下劃線在任何位置了
CGContextAddLines(context, poins, 4);
CGContextClosePath(context);
CGContextStrokePath(context);
}
}
其中主要是取CTFrameRef集合中的CTLines ,在其中他包含了字符的各種屬性,rang等
第一次寫文章,主要是當(dāng)時(shí)搞這個(gè)東西走了彎路,對(duì)coreText的不了解,也在csdn和cocoachina上問了好多人,都沒解決,防止以后忘記,自己再紀(jì)錄一下。
我目前做的項(xiàng)目是做的小說閱讀器,網(wǎng)上的素材真的是不多,現(xiàn)在也算是寫的差不多了,但是在預(yù)加載,內(nèi)存緩存和磁盤緩存上做的還是不行,希望有做閱讀器這方面有好的方案的,希望可以教教小弟,第一篇小文 也就搞定勒。