CoreText Demo1 文本

2020-08-11  本文已影响0人  coder_feng
CoreText对文本和图片的绘制是依赖NSAttributedString属性字符串的,CoreText的绘制过程,可以通过下面的图片来了解 Layout Flow

流程图的意思大概就是:获取context->翻转坐标系->创建属性NSAttributedString->根据NSAttributedString创建CTFramesetterRef->创建绘制区域CGPathRef->根据CTFramesetterRef和CGPathRef创建CTFrame->CTFrameDraw绘制

 CTFrame是指整个该UIView子控件的绘制区域,CTLine则是指每一行,CTRun则是每一段具有一样属性的字符串。比如某段字体大小、颜色都一致的字符串为一个CTRun,CTRun不可以跨行,不管属性一致或不一致。通常的结构是每一个CTFrame有多个CTLine,每一个CTLine有多个CTRun

代码如下:

- (void)drawRect:(CGRect)rect {
    // Drawing code
    [super drawRect:rect];
    //1.获取上下文
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    
    //[a,b,c,d,tx,ty]
    NSLog(@"转换前的坐标:%@",NSStringFromCGAffineTransform(CGContextGetCTM(contextRef)));
    //2.转换坐标系,CoreText的原点在左下角,UIKit原点在左上角
    CGContextSetTextMatrix(contextRef, CGAffineTransformIdentity);
    
    //3.这两种转换坐标的方式一样
//    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:20] range:NSMakeRange(0, 5)];
    [attributed addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(6, attributed.length - 6)];
     [attributed addAttribute:(id)kCTForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(0, 5)];
    
    //设置行距等样式
    CGFloat lineSpace = 10;//行距一般取决于这个值
    CGFloat lineSpaceMax = 20;
    CGFloat lineSpaceMin = 2;
    const CFIndex kNumberOfSettings = 3;
    
    //结构体数组
    CTParagraphStyleSetting settings[kNumberOfSettings] = {
        {kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),&lineSpace},
        {kCTParagraphStyleSpecifierMaximumLineSpacing,sizeof(CGFloat),&lineSpaceMax},
        {kCTParagraphStyleSpecifierMinimumLineSpacing,sizeof(CGFloat),&lineSpaceMin}
    };
    
    CTParagraphStyleRef paragraphRef = CTParagraphStyleCreate(settings, 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)(paragraphRef) range:NSMakeRange(0, attributed.length)];
    
    CFRelease(paragraphRef);
    
    //5.根据NSArrtibute
    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);

}
效果图 Snip20200810_5.png
上一篇下一篇

猜你喜欢

热点阅读