本篇教程爲第一篇,僅實如今一個UIView的子控件上繪製純文本。php
Github地址:https://github.com/JlongTian/JLCoreTextOnehtml
學習CoreText須要有一些基礎知識儲備,關於字符和字形的知識請點擊這裏以及這裏。另外還須要對NSAttributedString有一些瞭解,CoreText對文本和圖片的繪製就是依賴於NSAttributedString屬性字符串
的。ios
說下CoreText的繪製過程,先上一張圖片:git
整個流程大概是:獲取上下文-》翻轉座標系-》建立NSAttributedString-》根據NSAttributedString建立CTFramesetterRef-》建立繪製區域CGPathRef-》根據CTFramesetterRef和CGPathRef建立CTFrame-》CTFrameDraw繪製。github
上圖大概顯示了後半部分的結構。 CTFrame是指整個該UIView子控件的繪製區域,CTLine則是指每一行,CTRun則是每一段具備同樣屬性的字符串。好比某段字體大小、顏色都一致的字符串爲一個CTRun,CTRun不能夠跨行,無論屬性一致或不一致。一般的結構是每個CTFrame有多個CTLine,每個CTLine有多個CTRun。數組
本次純文本實現的效果圖以下:學習
控制器的代碼處理很簡單,UIView子控件的drawRect的代碼以下:字體
-(void)drawRect:(CGRect)rect{ [super drawRect:rect]; // 1.獲取上下文 CGContextRef contextRef = UIGraphicsGetCurrentContext(); // [a,b,c,d,tx,ty] NSLog(@"轉換前的座標:%@",NSStringFromCGAffineTransform(CGContextGetCTM(contextRef))); // 2.轉換座標系,CoreText的原點在左下角,UIKit原點在左上角 CGContextSetTextMatrix(contextRef, CGAffineTransformIdentity); // 這兩種轉換座標的方式效果同樣 // 2.1 // CGContextTranslateCTM(contextRef, 0, self.bounds.size.height); // CGContextScaleCTM(contextRef, 1.0, -1.0); // 2.2 CGContextConcatCTM(contextRef, CGAffineTransformMake(1, 0, 0, -1, 0, self.bounds.size.height)); NSLog(@"轉換後的座標:%@",NSStringFromCGAffineTransform(CGContextGetCTM(contextRef))); // 3.建立繪製區域,能夠對path進行個性化裁剪以改變顯示區域 CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, self.bounds); // CGPathAddEllipseInRect(path, NULL, self.bounds); // 4.建立須要繪製的文字 NSMutableAttributedString *attributed = [[NSMutableAttributedString alloc] initWithString:@"這是個人第一個coreText demo,我是要給兵來自老白乾I型那個餓哦個呢給個I類回滾yes we can 評估後共和國開不開vbdkaphphohghg 的分工額好幾個遼寧省更怕hi維護你不看hi好人佛【井柏然把餓哦個"]; [attributed addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20] range:NSMakeRange(0, 5)]; // 兩種方式皆可 [attributed addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(3, 10)]; [attributed addAttribute:(id)kCTForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(0, 2)]; // 設置行距等樣式 CGFloat lineSpace = 10; // 行距通常取決於這個值 CGFloat lineSpaceMax = 20; CGFloat lineSpaceMin = 2; const CFIndex kNumberOfSettings = 3; // 結構體數組 CTParagraphStyleSetting theSettings[kNumberOfSettings] = { {kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),&lineSpace}, {kCTParagraphStyleSpecifierMaximumLineSpacing,sizeof(CGFloat),&lineSpaceMax}, {kCTParagraphStyleSpecifierMinimumLineSpacing,sizeof(CGFloat),&lineSpaceMin} }; CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, kNumberOfSettings); // 單個元素的形式 // CTParagraphStyleSetting theSettings = {kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),&lineSpace}; // CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(&theSettings, kNumberOfSettings); // 兩種方式皆可 // [attributed addAttribute:(id)kCTParagraphStyleAttributeName value:(__bridge id)theParagraphRef range:NSMakeRange(0, attributed.length)]; // 將設置的行距應用於整段文字 [attributed addAttribute:NSParagraphStyleAttributeName value:(__bridge id)(theParagraphRef) range:NSMakeRange(0, attributed.length)]; CFRelease(theParagraphRef); //設置字間距 long number = 2.0; CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number); [attributed addAttribute:(id)kCTKernAttributeName value:(__bridge id)num range:NSMakeRange(0,[attributed length])]; CFRelease(num); // 5.根據NSAttributedString生成CTFramesetterRef CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributed); CTFrameRef ctFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, NULL); // 6.繪製除圖片之外的部分 CTFrameDraw(ctFrame, contextRef); // 7.內存管理,ARC不能管理CF開頭的對象,須要咱們本身手動釋放內存 CFRelease(path); CFRelease(framesetter); CFRelease(ctFrame); } 在整個繪製過程當中,NSMutableAttributedString是最重要的,給字符串設定不一樣的字體大小,顏色,乃至行距都是靠它,包括後面用空白佔位符來給圖片佔位,也依然是依賴該字符串。