CoreText--渲染Attribute

`test`

通过 CTFrameRef 渲染文本attribute样式

```

    - (void)drawRect:(CGRect)rect {

        if (self.frameRef == NULL) {

        return;

      }

       CGContextRef ctx = UIGraphicsGetCurrentContext();

       CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);

       CGContextFillRect(ctx, rect);

       CGContextSaveGState(ctx);

      [self flipContextCoordinate:ctx];

      CTFrameDraw(self.frameRef, ctx);

      CGContextRestoreGState(ctx);

     }

//Core Text是Apple的文字渲染引擎,坐标系为自然坐标系,即左下角为坐标原点,而iOS坐标原点在左上角。

//所以,在iOS上用Core Text绘制文字时,需要转换坐标系

  - (void)flipContextCoordinate:(CGContextRef)ctx{

      //以上下文中心旋转180

    CGContextScaleCTM(ctx, 1, -1);

      //向下平移视图

    CGContextTranslateCTM(ctx, 0, -CGRectGetHeight(self.bounds));

}

```

备注:坐标转换可以参考这里学习一下哦

蒙版实现

一 . 单词蒙版的原理是:以文本背景颜色为分割条件进行渲染,没有背景色的不再渲染(即为默认白色),有背景颜色的以设置的蒙版色填充(如灰色),达到蒙版的效果。

默认不填背景色,再逐一为单词填充背景色(达到空格等符号无背景,并且CTRun分割)

备注:一个CTRun为CTLine中样式一致的元素,样式一致的话一行就一个CTRun, 所以分别添加背景分割为多个单词的CTRun.

```

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:@"  You  go  first. -  No  you  go  first." attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor],

        NSFontAttributeName: [UIFont systemFontOfSize:14.0],

        NSParagraphStyleAttributeName: [self paragraphStyle]

        }];

    NSArray *subStrArray = [attributedText.string componentsSeparatedByString:@" "];

    NSInteger rangeOffset = 0;

    for (int i = 0; i < subStrArray.count; i++) {

        //空格分开的文本

        NSString *textSub = subStrArray[i];

        NSRange range = NSMakeRange(0, 0);

        range.length = textSub.length;

        rangeOffset += range.length;

        if (i != 0) {

            range.location += 1;

            range.location = rangeOffset;

        }

      [attributedText addAttributes:[self publicAttributes] range:range];

    }

```

根据CTFrame、CTLine和CTRun的结构生成CGPath确定的区域,然后绘制。

```

- (void)drawRect:(CGRect)rect {

    if (self.frameRef == NULL) {

        return;

    }

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);

    CGContextFillRect(ctx, rect);

    CGContextSaveGState(ctx);

//极坐标转迪卡尔坐标。旋转180度再平移

  [self flipContextCoordinate:ctx];

  CTFrameDraw(self.frameRef, ctx);

  CGContextRestoreGState(ctx);

//如果不需要蒙版效果,只是渲染文本attribute,上面就完成了

    if (!self.runMasked){return;} 

        CFArrayRef lines = CTFrameGetLines(self.frameRef);

        CFIndex lineCount = CFArrayGetCount(lines);

        CGPoint origins[lineCount];

        CTFrameGetLineOrigins(self.frameRef, CFRangeMake(0, 0), origins);

        CGMutablePathRef maskedPath = CGPathCreateMutable();

        for (int i=0; i

            CGPoint lineOrigin = origins[i];

            CTLineRef line = CFArrayGetValueAtIndex(lines, i);

            CFArrayRef runs = CTLineGetGlyphRuns(line);

            CFIndex runCount = CFArrayGetCount(runs);

            CGFloat lineAscent, lineDescent;

            CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, NULL);

            for (int j = 0; j

                CTRunRef runref = CFArrayGetValueAtIndex(runs, j);

                CFRange runRange = CTRunGetStringRange(runref);

                CFDictionaryRef runAttributeDic = CTRunGetAttributes(runref);

                Boolean hasBGAtt = CFDictionaryContainsKey(runAttributeDic, NSBackgroundColorAttributeName);

              if (!hasBGAtt) {

                  //没有背景色

                  continue;

              }

                CGFloat runDescent, leading;

                double width = CTRunGetTypographicBounds(runref,CFRangeMake(0, 0), NULL, &runDescent, &leading);

                CGFloat startOffSet = CTLineGetOffsetForStringIndex(line, runRange.location, NULL);

                //coretext坐标从左下角开始,第一行在最上面,纵坐标最大

                CGPoint runOri = lineOrigin;

                runOri.x += startOffSet;

                runOri.y += lineAscent;

                //iOS坐标从左上开始,coretext从左下开始,y轴坐标系转化

                runOri.y = CGRectGetHeight(self.bounds) - runOri.y;

                CGRect runBounds =

                (CGRect){.origin = runOri,

                        .size = {.width = width,

                                  .height = lineAscent + lineDescent}};

                CGPathAddRect(maskedPath, NULL, runBounds);

            }

        }

        CGContextAddPath(ctx, maskedPath);

        CGPathRelease(maskedPath);

        CGContextSetFillColorWithColor(ctx, [UIColor lightGrayColor].CGColor);

        CGContextFillPath(ctx);

}

```

其中坐标转换可以优化一下

```

- (void)drawRect:(CGRect)rect {

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);

    CGContextFillRect(ctx, rect);

//极坐标转迪卡尔坐标。旋转180度再平移

  [self flipContextCoordinate:ctx];

  //保留坐标转换效果

    CGContextSaveGState(ctx);

    、、略、、

    CGFloat runDescent, leading;

    double width = CTRunGetTypographicBounds(runref,CFRangeMake(0, 0), NULL, &runDescent, &leading);

    CGFloat startOffSet = CTLineGetOffsetForStringIndex(line, runRange.location, NULL);

    CGPoint runOri = lineOrigin;

    runOri.x += startOffSet;

    runOri.y -= lineDescent;

    CGRect runBounds = (CGRect){.origin = runOri, .size = {.width = width,

                                  .height = lineAscent + lineDescent}};

    、、略、、

    }

```

二. 不处理CTRun重绘,设置单词和前景色和背景色都为蒙版颜色,达到伪装效果(哈哈哈)

注意:边角为直角,如果需要绘制圆角之类的需要使用上一种方式哦。

```

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:@"  You go first. - No you go first." attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor],

        NSFontAttributeName: [UIFont systemFontOfSize:14.0],

        NSParagraphStyleAttributeName: [self paragraphStyle]

        }];

        NSArray *subStrArray = [attributedText.string componentsSeparatedByString:@" "];

  NSInteger rangeOffset = 0;

  for (int i = 0; i < subStrArray.count; i++) {

    //空格分开的文本

      NSString *textSub = subStrArray[i];

    NSRange range = NSMakeRange(0, 0);

    range.length = textSub.length;

    rangeOffset += range.length;

    if (i != 0) {

          range.location += 1;

          range.location = rangeOffset;

      }

      [attributedText addAttributes:@{NSForegroundColorAttributeName:[UIColor blueColor],

              NSBackgroundColorAttributeName:[UIColor blueColor],

              NSFontAttributeName: [UIFont systemFontOfSize:14.0]} range:range];

}

```

你可能感兴趣的:(CoreText--渲染Attribute)