总结在项目中使用DTCoreText时,遇到一些问题和解决方法。
安装运行 GitHub 地址: https://github.com/Cocoanetics/DTCoreText
官方文档: https://docs.cocoanetics.com/DTCoreText
直接下载下的DTCoreText是不能直接运行的,会报一些头文件找不到的错’import <DTFoundation/DTWeakSupport.h> file not found.’原因是DTCoreText依赖第DTFoundation这个库,所以需要执行一些操作安装DTFoundation库。
在本地新建一个文件DTCoreText,打开终端进入这个这个文件下 git clone git@github.com:Cocoanetics/DTCoreText.git git submodule init git submodule update
然后运行DTCoreText.xcodeproj,在使用的时候建议使用pod 'DTCoreText
来安装。
直接在终端上执行: git clone --recursive https://github.com/Cocoanetics/DTCoreText.git Externals/DTCoreText
安装文档:https://docs.cocoanetics.com/DTCoreText/docs/Setup%20Guide.html
显示文本 NSString *html = @"<p>这是一段使用<strong>DTCoreText</strong>显示的富文本</p><p>这是第二段使用<span style=\"text-decoration:underline;\">DTCoreText</span>显示的富文本</p>";
现在我们拿到一段html字符串,转换成NSAttributedString对象,然后使用DTCoreText的DTAttributedLabel进行显示。 DTCoreText 目前没有设置段间距的属性,只能丢到源码里,然后去解析这些属性,NSString *tag = @”“; 放到前面,设置段间距。这里涉及到一些html的东西。
- (NSAttributedString *)configAttributedString:(NSString *)html { NSString *tag = @"<style>p{margin:2 auto}</style>"; // 配置段间距 if (![html containsString:tag]) { html = [tag stringByAppendingString:html]; } NSDictionary *options = @{ DTDefaultFontSize:[NSNumber numberWithFloat:kFontSize(48)], // 字体大小 DTDefaultLineHeightMultiplier:[NSNumber numberWithFloat:1.5], //行间距 DTDefaultFontName:@"Helvetica"}; // 设置字体 NSData *data = [html dataUsingEncoding:NSUTF8StringEncoding]; return [[NSAttributedString alloc] initWithHTMLData:data options:options documentAttributes:NULL]; }
获取渲染后的大小
NSAttributedString *attributedString = ... DTCoreTextLayouter *layouter = [[DTCoreTextLayouter alloc] initWithAttributedString:attributedString]; CGRect maxRect = CGRectMake(10, 20, CGFLOAT_WIDTH_UNKNOWN, CGFLOAT_HEIGHT_UNKNOWN); NSRange entireString = NSMakeRange(0, [attributedString length]); DTCoreTextLayoutFrame *layoutFrame = [layouter layoutFrameWithRect:maxRect range:entireString]; CGSize sizeNeeded = [layoutFrame frame].size;
显示图片和Gif动图 如果是一个本地html文件,里面的图片也是本地展示是没问题,如果远程图片这个时候需要更多一些操作了。在解析到<img></img>标签的时候插入一个占位符,然后在代理方法里面解析获取,通过封装的DTLazyImageView图片来显示
NSString *html = @"<p>这是一段使用<strong>DTCoreText</strong>显示的富文本</p><p>这是第二段使用<span style=\"text-decoration:underline;\">DTCoreText</span>显示的富文本</p><p><img src=\"http://7xj2sw.com1.z0.glb.clouddn.com/QQ20171013-223759@2x.png\" _src=\"http://7xj2sw.com1.z0.glb.clouddn.com/QQ20171013-223759@2x.png\" style=\"width:200px;height:100px;\"/></p>";
- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame { if([attachment isKindOfClass:[DTImageTextAttachment class]]) { NSString *imageURL = [NSString stringWithFormat:@"%@", attachment.contentURL]; DTLazyImageView *imageView = [[DTLazyImageView alloc] initWithFrame:frame]; imageView.delegate = self; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.image = [(DTImageTextAttachment *)attachment image]; imageView.url = attachment.contentURL; if ([imageURL containsString:@"gif"]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *gifData = [NSData dataWithContentsOfURL:attachment.contentURL]; dispatch_async(dispatch_get_main_queue(), ^{ imageView.image = DTAnimatedGIFFromData(gifData); }); }); } return imageView; } }
DTLazyImageView 异步下载这张图片,如果是一张gif图就不会动,需要下载完这个Gif的数据之后再做一次转换赋值。
如果上传的图片属性里面没有宽高属性style=\"width:200px;height:100px;
,是显示不出来的。官方给的一个解决方案是在DTLazyImageView的代理方法 - (void)lazyImageView:(DTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size 里面获取它的originalSize是否为CGSizeZero,然后重新赋值,刷新布局。
- (void)lazyImageView:(DTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size { NSURL *url = lazyImageView.url; CGSize imageSize = size; NSPredicate *pred = [NSPredicate predicateWithFormat:@"contentURL == %@", url]; BOOL didUpdate = NO; // update all attachments that match this URL (possibly multiple images with same size) for (DTTextAttachment *oneAttachment in [self.layoutFrame textAttachmentsWithPredicate:pred]) { // update attachments that have no original size, that also sets the display size if (CGSizeEqualToSize(oneAttachment.originalSize, CGSizeZero)) { oneAttachment.originalSize = imageSize; didUpdate = YES; } } if (didUpdate) { // do it on next run loop because a layout pass might be going on self.layouter = nil; [self relayoutText]; } }
但是展示View大小是有限制的,这个时候绘制的图片超出可视区域。目前想到一个解决方案是在- (void)lazyImageView:(DTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size 难道图片的size之后平凑出style的宽高属性。然后在重新初始化加载这个html字符串。
// 字符串中一些图片没有宽高,需要这里拿到宽高后再去reload - (void)configNoSizeImageView:(NSString *)url size:(CGSize)size { NSString *imageInfo = [NSString stringWithFormat:@"_src=\"%@\"",url]; NSString *sizeString = [NSString stringWithFormat:@" style=\"width: %.fpx; height: %.0fpx;\"",size.width,size.height]; NSString *newImageInfo = [NSString stringWithFormat:@"_src=\"%@\"%@",url,sizeString]; if ([self.html containsString:imageInfo] && !self.isClose) { NSString *newHtml = [self.html stringByReplacingOccurrencesOfString:imageInfo withString:newImageInfo]; // reload newHtml } }
至于为什么会有 src 和 _scr ? 使用了百度开源了一个富文本编辑器UEditorhttp://ueditor.baidu.com/website/onlinedemo.html 传图片的时候就会有多个 _scr,属性也都在这里面,所以就追加到_scr里面。
显示自定义控件 在展示自定义控件里展示输入框和数学公式
显示公式 [DTTextAttachment registerClass:[DTObjectTextAttachment class] forTagName:@"object"];
<p> <span class="mathquill-embedded-latex" style="width: 26px; height: 41px;">\frac{2}{3}</span>是一个分数,1 小于<span class="mathquill-embedded-latex" style="width: 41px; height: 28px;">\sqrt{2}</span>。 </p>
我想自定定义控件的tagname为“mathquill-embedded-latex”,并不可以但是替换成“object”就可以,这里使用正则表达式替换mathquill-embedded-latex为object。然后拿到文本使用第三方库iosMathhttps://github.com/kostub/iosMath 显示公式。
// 公式需要自定义标签,如果包含数学公式标签才处理,不需要每次正则表达式去匹配 - (NSString *)configMathlatex:(NSString *)html { NSString *string = html; if ([string containsString:@"<span class=\"mathquill-embedded-latex\""]) { NSError *error = nil; NSString *pattern = @"<span class=\"mathquill-embedded-latex\" style=.*?>.*?</span>"; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error]; NSArray *array = [regex matchesInString:string options:NSMatchingReportProgress range:NSMakeRange(0, [string length])]; for (NSInteger i = array.count-1; i>=0; i--) { NSTextCheckingResult *result = array[i]; NSString *latextext = [string substringWithRange:result.range]; // 需要变更的字符串 [string deleteCharactersInRange:result.range]; NSString *objectText = [latextext stringByReplacingOccurrencesOfString:@"span" withString:@"object"]; [string insertString:objectText atIndex:result.range.location]; } } return string; }
显示输入框 [DTTextAttachment registerClass:[DTObjectTextAttachment class] forTagName:@"input"];
- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame { if ([attachment isKindOfClass:[DTObjectTextAttachment class]]){ NSString *className = [attachment.attributes objectForKey:@"class"]; if ([className isEqualToString:@"mathquill-embedded-latex"]) { // 公式 attachment.verticalAlignment = DTTextAttachmentVerticalAlignmentCenter; DTObjectTextAttachment *element = (DTObjectTextAttachment *)attachment; NSString *content; for (DTHTMLElement *oneChildElement in element.childNodes) { content = oneChildElement.text; MTMathUILabel* label = [[MTMathUILabel alloc] init]; label.textAlignment = kMTTextAlignmentCenter; label.frame = frame; label.latex = content; label.fontSize = 16; return label; } } NSString *type = [attachment.attributes objectForKey:@"type"]; if ([type isEqualToString:@"text"]) { // 文本输入框 UITextField *textField = self.textFieldArray[tfID]; textField.frame = frame; textField.contentVerticalAlignment=UIControlContentVerticalAlignmentCenter; textField.layer.cornerRadius = 6; textField.delegate = self; textField.leftViewMode = UITextFieldViewModeAlways; textField.rightViewMode = UITextFieldViewModeAlways; [textField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter]; return textField; } } }
参考资料:
https://docs.cocoanetics.com/DTCoreText
http://blog.cnbang.net/tech/2630
http://blog.cnbang.net/tech/2729
http://www.jianshu.com/p/9f5ac4d47ef4
当你获得的越多,你就会越温柔,不会为一点失去就气得暴跳如雷,也不会因为别人的否定就变得愤怒又消极。好的成长,就该是让人变得越来越温柔。