`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
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}}; 、、略、、 } ``` 注意:边角为直角,如果需要绘制圆角之类的需要使用上一种方式哦。 ``` 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 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]; } ```二. 不处理CTRun重绘,设置单词和前景色和背景色都为蒙版颜色,达到伪装效果(哈哈哈)