YYText之图文混排
1.图文混排的原理?
我觉得,查看代码前,最重要的一件事是知道图文混排到底是怎么实现的。
核心思想:生成富文本时把,一张图片先用一个占位符代替。实际渲染时,图片占位符的渲染处理会更多一些。
根据这个原理,我们开始深入的学习。本文Demo基于YYKitExample。
2.YYTextAttachmentExample
我们先看YYTextAttachmentExample.m中的代码实现。self.view上有3个富文本,并且末尾都带了图片。我们可以看出,设置富文本的核心方法如下,深入看看其中做了什么。
+ (NSMutableAttributedString *)attachmentStringWithContent:(id)content
contentMode:(UIViewContentMode)contentMode
attachmentSize:(CGSize)attachmentSize
alignToFont:(UIFont *)font
alignment:(YYTextVerticalAlignment)alignment;
结合代码运行流程,我们分为以下几个部分:
2.1 生成NSMutableAttributedString实例
初始化时提供了一个占位符@"\uFFFC",用于代替图片信息。
2.2 YYTextAttachment
说到图文混排,必然会用到NSTextAttachment,它是NSAttributedString的类簇,设置富文本时对应的key是NSAttachmentAttributeName。简而言之,我们给一个NSAttributedString实例添加图片时,就是将image实例作为以上key的value。YYText自身实现了一个YYTextAttachment,作者是这么介绍的:
YYTextAttachment是NSAttributedString的类簇,它的实例作为富文本key属性YYTextAttachmentAttributeName的value。当富文本包含YYTextAttachment时,它会采用文本规则展示。比如,attachment的内容是UIImage时,它会被绘制为CGContext;attachment的内容是UIView或CALayer时,它会被加入到text container的view层或layer层上。
2.3 YYTextRunDelegate
在这之前我们先要知道,NSAttributedString相比于NSString多了很多attribute的概念,比如下划线、背景色等。每个字符都有一个字符区域,渲染每个字符多种多样的attributes都是在这个区域的基础上的。转换成代码是什么意思呢?CoreText的为我们提供了这个体系:
CTFrame.jpg
NSAttributedString初始化后会生成CTFramesetter,CTFramesetter根据不同的CGPath生成对应的CTFrame,一个CTFrame由多行CTLine组成,一个CTLine会包含多个CTRun(字形绘制的最小单元)。
结合之前说的绘制的核心思想,可以这么理解:一行带有文字和图片的富文本,包含若干个CTRun绘制单元,图片的绘制单元相对特殊一些。为什么呢?因为CoreText并不能直接将一个图片转换为CTRun来绘制,所以它先用占位符预留空间,而真正的图片绘制是交给CoreGraphics完成的。
问题又来了,CoreGraphics是如何拿到这些绘图信息(descent、ascent、width等)呢?到这终于引出了CTRunDelegate。我们为富文本的kCTRunDelegateAttributeName属性赋值一个CTRunDelegate实例,CoreText可以根据它拿到它内部的属性,如descent、ascent、width等。
2.4 小结
通过以上3个步骤,一个富文本就生成了。其中涉及到了CoreText的许多类,尤其是NSTextAttachment和CTRunDelegate。还有,富文本的文本结构。详细内容,推荐《Text Programming Guide for iOS》