Graver文字绘制核心类

2020-02-11  本文已影响0人  Bel李玉

美团开源Graver框架:用“雕刻”诠释iOS端UI界面的高效渲染
Graver初探中,探索了Graver的绘制周期。本着一探究竟的心态,来探索Graver具体的绘制过程和涉及的核心类。
Graver中绘制的核心类主要为:WMGTextDrawer,WMGTextLayout,WMGTextLayoutFrame,WMGTextLayoutLine,WMGTextLayoutRun.每个类的主要方法和作用我做了一个简单的汇总,如下图所示:

Graver核心类.png

WMGTextLayoutRun:根据文本组件,创建一个CTRunDelegateRef对象,在CoreText的图文混排中,具体的实现是:在一个NSAttributeString中插入一个空字符\uFFFC作为占位符,由CTRunDelegateRef确定该字符的widthheight,预留出图片的位置。在NSAttributeString绘制完成后,在将图片绘制到根据CTRunDelegateRef预留出来的区域中。

WMGTextLayoutLine:行信息,根据CTLine获取该行的_lineWidth(行宽),是否截断中划线等信息,CTLineGetGlyphRuns方法通过CTLine可以得到对应行的CTRun信息。CTLineGetStringIndexForPosition方法可以通过点击点获得点击点的字符在该行中的位置。

WMGTextLayoutFrame:根据CTFrameRef获得。1,通过CTFrameRef确定layoutSize。2,根据CTFrameRef得到CTLine和每一个CTLine的基线原点。3,依据textLayout的最大行数,确定是否需要截断,更换截断字符。4,将CTLine的信息保存到WMGTextLayoutLine中。

WMGTextLayout:文字的布局对象。主要包括NSAttributeStringmaximumNumberOfLinesheightSensitiveLayout, baselineFontMetrics,当任意一个属性变化时,就会根据NSAttributeString自动创建一个WMGTextLayoutFrame

WMGTextDrawer:文字绘制对象。通过- (void)drawInContext:(CGContextRef)ctx visibleRect:(CGRect)visibleRect replaceAttachments:(BOOL)replaceAttachments shouldInterruptBlock:(WMGTextDrawerShouldInterruptBlock)block方法进行绘制,WMGTextDrawer通过frame属性设置总的绘制区域,根据WMGTextLayout中的WMGTextLayoutFrame,然后根据WMGTextLayoutLineCTLine进行逐行绘制(CTLineDraw)。另外WMGTextDrawerDelegate:负责对NSAttributeString中的WMGAttachment进行绘制。WMGTextDrawerEventDelegate:负责处理图文混排中,图片,文字,超链接,电话的点击事件。WMGActiveRange:响应点击事件的文字区域。

接下来我们直接通过WMGTextDrawer进行绘制,新建ExampleView,重写-(void)drawRect:(CGRect)rect

   _attrStr = [[NSMutableAttributedString alloc] initWithString:@"这些喜欢矫"];

        // 新建图片组件信息
        WMGTextAttachment *attachment = [[WMGTextAttachment alloc] init];
        attachment.type = WMGAttachmentTypeStaticImage;
        attachment.contents = [UIImage imageNamed:@"aiqing"];
        attachment.size = CGSizeMake(40, 40);
        attachment.position = 5;// 在字符串中的index
        attachment.length = 1;// 所占字符长度
        attachment.userInfo = @{@"content": attachment.contents};
        self.textAttachment = attachment;

        // 设置占位符的高度
        WMGFontMetrics fontMetric = WMGFontMetricsMake(attachment.size.height, 0, 0);
        attachment.baselineFontMetrics = fontMetric;

        // 给图片添加点击事件
        [attachment addTarget:self action:@selector(clickAction:) forControlEvents:UIControlEventTouchUpInside];

        NSAttributedString *str1 = [NSAttributedString wmg_attributedStringWithTextAttachment:attachment];

        NSAttributedString *str2 = [[NSAttributedString alloc] initWithString:@"枉过正的中国近代知识分子,他们不否定读书人群体存在的必要性,但主张自己要和工人打成一片"];
        [_attrStr appendAttributedString:str1];
        [_attrStr appendAttributedString:str2];
        [_attrStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20] range:NSMakeRange(0, _attrStr.string.length)];

        NSMutableAttributedString *strdd = [[NSMutableAttributedString alloc] initWithString:_attrStr.string];
        // 拼接文本组件信息
        [strdd addAttribute:WMGTextAttachmentAttributeName value:attachment range:NSMakeRange(5, 1)];
        CTRunDelegateRef delegate = [WMGTextLayoutRun textLayoutRunWithAttachment:attachment];
        [strdd addAttribute:(NSString * )kCTRunDelegateAttributeName value:(__bridge id )delegate range:NSMakeRange(5, 1)];

        // 添加蓝色字体
        [strdd addAttribute:(NSString *)kCTForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(8, 5)];

        [strdd addAttribute:(NSString *)kCTFontAttributeName value:[UIFont systemFontOfSize:17] range:NSMakeRange(0, strdd.string.length)];


        _textDrawer = [[WMGTextDrawer alloc] init];
        // frame 必须设置
        _textDrawer.frame = self.bounds;
        // 设置最大行数
        _textDrawer.textLayout.maximumNumberOfLines = 2;
        _textDrawer.textLayout.attributedString = strdd;
        // 设置点击事件代理
        _textDrawer.eventDelegate = self;

看下效果:


Simulator Screen Shot - iPhone.png

最后附上CoreTex图文混排WMGTextDrawer图文混排的Demo

上一篇 下一篇

猜你喜欢

热点阅读