coreText绘制文本
我们需要知道我们是将用Coretext布局好的文本图片信息绘制在view上,并在view的drawRect方法。现在我们先初步了解一下步骤:
- 首先,我们需要根据要显示的文本以及文本属性初始化一个NSMutableAttributedString;
- 根据文本以及文本属性配置CTFramesetterRef;
- 设置绘制区域(CGPathRef),并根据绘制区域和CTFramesetterRef生成CTFrameRef;
- 最后将排版好的文本绘制到view上。
为了使代码结构清晰,可以将配置文本属性(包括字体大小,行间距等信息)写成一个类,再用一个类去排版布局文本,最后将排版好的文本绘制在view上。
- 首先根据要显示的文本以及文本属性生成NSMutableAttributedString
//content就是要显示的文本内容 NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:content]; //config是用来记录文本属性(包括字体大小,字体颜色等信息)的类的对象 NSMutableDictionary *dict = [NSMutableDictionary dictionary]; //记录字体大小 dict[NSFontAttributeName] = [UIFont systemFontOfSize:config.fontSize]; //字体颜色 dict[NSForegroundColorAttributeName] = config.fontColor; //行间距 NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; style.lineSpacing = config.lineSpace; style.alignment = NSTextAlignmentJustified; dict[NSParagraphStyleAttributeName] = style; //设置属性以及文本内容(也可以分别设置字体大小,字体颜色等属性) [attString addAttributes:dict range:NSMakeRange(0, content.length)]; //两个参数分别是文本属性、该文本属性约束的文本范围 //这里将整个文本(NSMakeRange(0, content.length))设置成了同一种样式,我们也可以根据自己的需求分别设置每一段的字体样式,也可以加下划线,字体加粗等。
- 根据文本以及文本属性配置CTFramesetterRef
CTFramesetterRef setterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attString);
注:这里需要将OC对象转为CF对象,__bridge表示在将OC对象转为CF对象时不涉及对象转换,所以转换后不需要手动释放attString
- 设置绘制区域,并根据绘制区域和CTFramesetterRef生成CTFrameRef
//文本要布局显示的区域 CGPathRef pathRef = CGPathCreateWithRect(bounds, NULL); //将CFRangeMake(0, 0)length设为0布局会根据CTFramesetterRef在pathRef区域内一直排版直到排满 CTFrameRef frameRef = CTFramesetterCreateFrame(setterRef, CFRangeMake(0, 0), pathRef, NULL); //第一个参数是待排版的CTFramesetterRef,第二个参数是排版的文字范围,第三个参数是排版区域。 CFRelease(setterRef); CFRelease(pathRef);
注:ARC环境下编译器不会自动管理CF对象的内存,需要手动释放
- 以上内容写在一个用于排版的类(生成CTFrameRef)中,通过这个类获取到 CTFrameRef后,在view里重写drawRect方法,将布局好的文本绘制到view上
-
- (void)drawRect:(CGRect)rect{ if (!_frameRef) {//在view中声明了一个CTFrameRef return; } //翻转坐标系 CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSetTextMatrix(ctx, CGAffineTransformIdentity); CGContextTranslateCTM(ctx, 0, self.bounds.size.height); CGContextScaleCTM(ctx, 1.0, -1.0); //绘制到view CTFrameDraw(_frameRef, ctx); }
注:CoreText坐标系和UIKit坐标系的不同,绘制之前我们需要将坐标系统一; _frameRef不会自动释放,我们必须要手动释放掉。
-(void)setFrameRef:(CTFrameRef)frameRef{ if (_frameRef != frameRef) { if (_frameRef) { //释放_frameRef CFRelease(_frameRef); _frameRef = nil; } _frameRef = frameRef; } } -(void)dealloc { if (_frameRef) { CFRelease(_frameRef); _frameRef = nil; } }