DTCoreText项目使用浅析 (2)
前一篇提到生成NSAttributedString,接下面就是如何将NSAttributedString展示出来
DTAttributedTextContentView的主要结构
@interface DTAttributedTextContentView : UIView { NSAttributedString *_attributedString; DTCoreTextLayoutFrame *_layoutFrame; UIEdgeInsets edgeInsets; NSMutableDictionary *customViewsForAttachmentsIndex; } - (id)initWithAttributedString:(NSAttributedString *)attributedString width:(CGFloat)width; - (void)resetWithLayouterWithFrame:(DTCoreTextLayouter *)layouter layoutFrame: (DTCoreTextLayoutFrame *)layoutFrame frame:(CGRect)frame; - (void)layoutSubviewsInRect:(CGRect)rect; - (void)relayoutText; - (void)removeAllCustomViews; - (void)removeAllCustomViewsForLinks; - (CGSize)attributedStringSizeThatFits:(CGFloat)width; - (CGSize)suggestedFrameSizeToFitEntireStringConstraintedToWidth:(CGFloat)width; // obeys the edge insets // properties are overwritten with locking to avoid problem with async drawing @property (atomic, strong) DTCoreTextLayouter *layouter; @property (atomic, strong) DTCoreTextLayoutFrame *layoutFrame; @property (nonatomic, strong) NSMutableSet *customViews;
其中有两个布局相关的元素:
@property (atomic, strong) DTCoreTextLayouter *layouter; @property (atomic, strong) DTCoreTextLayoutFrame *layoutFrame;
其中DTCoreTextLayoutFrame有个重要的方法叫做
- (void)_buildLines
这里就开始根据attributedString做各种段落和行数的设置了,局限于Coretext的知识,这里我无法给出一个详细的说明
DTAttributedTextContentView重载了layoutSubviews和实现了- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
NSAttributedString *layoutString = [theLayoutFrame attributedStringFragment]; NSArray *lines; if (CGRectIsInfinite(rect)) { lines = [theLayoutFrame lines]; } else { lines = [theLayoutFrame linesVisibleInRect:rect]; }
接着遍历line
for (DTCoreTextLayoutLine *oneLine in lines) { NSRange lineRange = [oneLine stringRange]; NSUInteger skipRunsBeforeLocation = 0; for (DTCoreTextGlyphRun *oneRun in oneLine.glyphRuns)
针对每个单元,查找link和attachment的属性,这里还对attachment的view做了缓存优化
if (_delegateFlags.delegateSupportsCustomViewsForAttachments) { newCustomAttachmentView = [_delegate attributedTextContentView:self viewForAttachment:attachment frame:frameForSubview]; } else if (_delegateFlags.delegateSupportsGenericCustomViews) { NSAttributedString *string = [layoutString attributedSubstringFromRange:runRange]; newCustomAttachmentView = [_delegate attributedTextContentView:self viewForAttributedString:string frame:frameForSubview]; }
委托生成对应的custom view, 这里可以做些图文混排的工作,比如图片、链接等
这里补充下,这里custom view生成时,可以动态调整相关高度,也就是说不用去更新nsattributedstring,动态加载图片就是这样处理的。
等custom view生成完毕后,开始调用
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
DTCoreTextLayoutFrame *theLayoutFrame = self.layoutFrame; // need to prevent updating of string and drawing at the same time SYNCHRONIZE_START(selfLock) { [theLayoutFrame drawInContext:ctx drawImages:shouldDrawImages]; if (_delegateFlags.delegateSupportsNotificationAfterDrawing) { [_delegate attributedTextContentView:self didDrawLayoutFrame:theLayoutFrame inContext:ctx]; } } SYNCHRONIZE_END(selfLock)
DTCoreTextLayoutFrame这个方法负责将构造出来的DTCoreTextLayoutLine数组,通过CoreText绘制到图形上下文中,还利用CoreGraphics画线、背景等一系列效果;这里也可以定制部分特殊效果功能。
这样DTCoreText的基本流程就完成了,里面很多细节没有涉及,和CoreText相关的功能还待学习。