CoreText绘制富文本

CoreText的绘制(使用CTFrameDraw直接绘制)

  • 简述:通过NSAttributedString来绘制富文本
  • 流程图:
    获取当前context->设置context->设置绘制区域->排版获取CTFrameRef->CTFrameDraw绘制->释放变量
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    
    //文字相关的属性都是由NSMutableAttributedString来设置的
    NSString *theString = @"君不见,黄河之水天上来,奔流到海不复回。君不见,高堂明镜悲白发,朝如青丝暮成雪。人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,将进酒,杯莫停。与君歌一曲,请君为我倾耳听。钟鼓馔玉不足贵,但愿长醉不复醒。古来圣贤皆寂寞,惟有饮者留其名。陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。";
    NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:theString];
    [attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:25] range:NSMakeRange(4, 5)];
    [attr addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:20] range:NSMakeRange(11, 4)];
    [attr addAttribute:NSForegroundColorAttributeName value:[UIColor purpleColor] range:NSMakeRange(3, 4)];
    
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    //向上平移一个视图高度的距离
    CGContextTranslateCTM(context, 0, self.bounds.size.height);
    //围绕x轴的翻转
    CGContextScaleCTM(context, 1.0, -1.0);
  
    // 创建绘制区域
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, self.bounds);
    
    //排版
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attr);
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attr length]), path, NULL);
    
    //整个区域绘制
    CTFrameDraw(frame, context);
    
    //释放
    CFRelease(frame);
    CFRelease(path);
    CFRelease(framesetter);
}
CoreText绘制富文本_第1张图片
image.png

使用CTLine一行一行绘制

为什么要一行一行绘制,因为CTFrameDraw一气呵成的绘制可能导致行高不一致

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    //同上...

    //一行一行绘制
    [self _drawText:frame];

    //释放
    CFRelease(paragraphRef);
    CFRelease(frame);
    CFRelease(path);
    CFRelease(framesetter);
}

/**
 一行一行的写字
 */
- (void)_drawText:(CTFrameRef)frameRef{
    CFArrayRef lines = CTFrameGetLines(frameRef);//获取lineRef数组
    CFIndex lineCount = CFArrayGetCount(lines);//获取lineRef数组的长度
    NSUInteger numberOfLines = lineCount;//默认显示所有文字
    CGPoint lineOrigins[numberOfLines];//将每一行起始位置组成一个数组
    CTFrameGetLineOrigins(frameRef, CFRangeMake(0, numberOfLines), lineOrigins);
    for (CFIndex idx = 0; idx < numberOfLines; idx ++) {//遍历每一行
        CGContextRef context = UIGraphicsGetCurrentContext();//获取每一行的上下文
        CTLineRef lineRef = CFArrayGetValueAtIndex(lines, idx);//每一行对应的lineRef
        CGContextSetTextPosition(context, lineOrigins[idx].x, lineOrigins[idx].y);//设置每一行的起始绘制位置
        CTLineDraw(lineRef, context);
    }
}
CoreText绘制富文本_第2张图片
image.png

设置行间距

给attr增加一个NSParagraphStyleAttributeName属性

   //设置行间距
    CGFloat lineSpacing = 30;
    const CFIndex num = 1;
    CTParagraphStyleSetting settings[num] = {{kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(CGFloat), &lineSpacing}};//数组
    CTParagraphStyleRef paragraphRef = CTParagraphStyleCreate(settings, num);
    [attr addAttribute:NSParagraphStyleAttributeName value:(__bridge id)(paragraphRef) range:NSMakeRange(0, attr.length)];

    //记得释放
    CFRelease(paragraphRef);

CoreText绘制富文本_第3张图片
image.png

恩和谐了很多

将CoreText转化成图片

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);

    //获取绘制文字的context...
    
    UIImage *screenShotimage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

这里UIGraphicsBeginImageContextWithOptions的参数解释如下:第一个表示生成图片的尺寸;第二个参数表示是否透明,0为不透明;第三个参数表示缩放因子,0表示生成图片自动根据屏幕分辨率的变化而变化

你可能感兴趣的:(CoreText绘制富文本)