图文混排实现
最近公司的项目需要用到图文混排编辑来书写个人简介,由于需求功能比较简单,所以找到了SimpleWord,个人感觉功能还是很强大的,但在实现需求过程中发现了一些问题,特此记录一下。
踩坑
1、在web上正常加载的图片(图1),通过富文本的下面的方式显示在textView上会出现图片宽高不适配的情况,如图2所示;
textView.attributedText = [[NSAttributedString alloc] initWithData:[autoStr dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
2、由于图片都是网络图片,显示在textView上如果不对图片进行修改,点击保存,用SimpleWord写好的的方法将原生的 AttributedString 导出成 HTML的方式,会存在<img src="null"/>的问题。
填坑
1、针对第一个问题,我将得到的html加上img的css样式,代码如下,完美解决图片不适配的问题!
NSString *autoStr = [NSString stringWithFormat:@"<head><style>img{width:%f !important;height:auto}</style></head>%@",SCREENW - 2*20,_htmlString];
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithData:[autoStr dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
2、针对第二个问题,图片标签src="null"的问题,这个问题还是困惑了很久的,后来通过查看他将原生的 AttributedString 导出成 HTML的方法,由于代码较长,就贴出导出img的方法;
可以分析得出导出img的思路是获取attributes中的NSAttachment类,在拿到NSAttachment的userInfo属性,但这个userInfo是NSAttachment的分类属性,我们转成attributedString时候并没有给他赋初值,所以直接对原来图片进行保存的话,肯定是没有值的!
NSDictionary *attributes = [attributedString attributesAtIndex:effectiveRange.location effectiveRange:&effectiveRange];
NSTextAttachment *attachment = attributes[@"NSAttachment"];
NSParagraphStyle *paragraph = attributes[@"NSParagraphStyle"];
LMParagraphConfig *paragraphConfig = [[LMParagraphConfig alloc] initWithParagraphStyle:paragraph type:LMParagraphTypeNone];
if (attachment) {
switch (attachment.attachmentType) {
case LMTextAttachmentTypeImage: // attachment.fileWrapper.preferredFilename
[htmlContent appendString:[NSString stringWithFormat:@"<img src=\"%@\" width=\"100%%\"/>", attachment.userInfo]];
break;
default:
break;
}
}
找到问题之后,接下来就是解决了,现在要做的就是在原来attributedString的基础上取出NSTextAttachment,并给其userInfo属性赋上我们的图片地址;参照图片生成NSTextAttachment 的方法
- (NSTextAttachment *)insertImage:(UIImage *)image;
我们在得出修改后的富文本字符串之前,我们要先拿到所有的img标签,在这里我用的是Hpple。
+ (NSArray *)getSrcArrWithHtmlString:(NSString *)htmlString {
NSData *data =[htmlString dataUsingEncoding:NSUnicodeStringEncoding];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; //data转字符串 为了打印不是乱码
SLog(@"------%@",result);
TFHpple *Hpple = [[TFHpple alloc]initWithHTMLData:data];
NSArray *array =[Hpple searchWithXPathQuery:@"//img"]; //获取到为img标签数组
NSMutableArray *secArr = [NSMutableArray array];
for (TFHppleElement *HppleElement in array) {
NSDictionary *node = HppleElement.attributes;
[secArr addObject:node[@"src"]];
}
return secArr;
}
最后,我们可以得出修改后的富文本字符串,大致代码如下;
// 改变attachment.userInfo
+ (NSAttributedString *)attStringFromAttributedString:(NSAttributedString *)attributedString textView:(UITextView *)textView htmlString:(NSString *)htmlString {
NSMutableAttributedString *copyAttr = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
NSRange effectiveRange = NSMakeRange(0, 0);
int section = 0;
NSArray *secArr = [self getSrcArrWithHtmlString:htmlString];
while (effectiveRange.location + effectiveRange.length < attributedString.length) {
NSDictionary *attributes = [attributedString attributesAtIndex:effectiveRange.location effectiveRange:&effectiveRange];
NSTextAttachment *attachment = attributes[@"NSAttachment"];
if (attachment) {
attachment.attachmentType = LMTextAttachmentTypeImage;
attachment.userInfo = secArr[section]; // 获取网络图片路径
section++;
//
NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:@"\n"];
[attributedStr insertAttributedString:attachmentString atIndex:0];
[attributedStr addAttributes:textView.typingAttributes range:NSMakeRange(0, attributedStr.length)];
// 添加样式
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
paragraphStyle.paragraphSpacingBefore = 8.f;
paragraphStyle.paragraphSpacing = 8.f;
[attributedStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, attributedStr.length)];
[copyAttr replaceCharactersInRange:effectiveRange withAttributedString:attributedStr];
}
effectiveRange = NSMakeRange(effectiveRange.location + effectiveRange.length, 0);
}
return copyAttr;
}
PS:由于我这次项目只是简单的图文编辑跟混排,需要的内容不是很多,所以采用NSAttributedString进行展示,如果需要大量的图片及文字展示,例如阅读类的APP,建议还是用coreText或textKit进行排版!