本文技术点涉及到NSAttrbutedString
链接:http://blog.csdn.net/a316212802/article/details/50519733
简述
CoreText是用于处理文字和字体的底层技术,它直接和Core Graphics(又名Quartz2D)交流。Quartz是一个2D图形渲染引擎,能够处理OS X和iOS的图形显示问题
Quartz能够直接处理字体(font)和字形(glyphs)将文字渲染到界面上,它是基础库中的唯一能够处理字形的模块。因此,Core Text为了排版,需要将显示的文本内容 位置 字体字形直接传递给Quartz。与其他UI组件相比由于Core Text直接和Quartz交互 所以它具有搞笑的排版功能。
以下是Core Text架构图 (iOS7之后)
从这幅图可以看出 上层UI控件包括UILabel UITextField和UIWebView都是基于Core Text实现的。
CoreText和UIWebView的排版比较
CoreText和UIWebView都是处理复杂文字排版的备选方案 对于排版而言 CoreText和UIWebView的比较
优点:
CoreText使用情景包括:新浪微博客户端,多看阅读客户端,猿题库。
Core Text内部结构如图
上图中大概显示了后半部分的结构,CTFrame 是指整个该UIView子控件的绘制区域,CTLine则是指每一行。CTRun则是每一段具有一样的属性的字符串 比如某段字体大小,颜色都一致的字符串为一个CTRun。CTRun不可以跨行,不管属性是否一致。通常的结构是每一个CTFrame有多个CTLine 每一个CTLine有多个CTRun。
一个简单的不包含图片链接等的文本显示demo的过程如下:
子控件的drawInRect代码如下:
- (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:@"关关雎鸠,在河之洲。窈窕淑女,君子好逑。 参差荇菜,左右流之。窈窕淑女,寤寐求之。求之不得,寤寐思服。悠哉悠哉,辗转反侧。参差荇菜,左右采之。窈窕淑女,琴瑟友之。参差荇菜,左右芼之。窈窕淑女,钟鼓乐之。"]; [attributed addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:18] range:NSMakeRange(0, 6)]; // 两种方式皆可 [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); // 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); }执行效果如下:
代码注意点:
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, self.bounds);
当前是用Quartz创建了矩形加入到区域路径中,如果替换为
CGPathAddEllipseInRect(path,NULL,self.bounds),则会发现可绘制区域变成一个椭圆。
下一篇将会涉及到图文混排的内容。