背景:最近AI对话比较热门,AI回复的内容有很多markdown格式,需要展示一下。
三方库:CocoaMarkdown
在github上搜索并下载源码到本地,打开工程文件,选择Any iOS Device编译成功后,在左侧文件栏最下面有一个Products目录,展开找到CocoaMarkdown.framework,将此文件复制到自己的工程,这里是真机的,需要使用模拟器的自己选择模拟器编译进行后再合并,这里不叙述。
下面是关键代码,计算高度
// 导入
#import <CocoaMarkdown/CocoaMarkdown.h>
self.aiResWidth = k_screen_width - 55 - 26 - 10;
DLog(@"self.dadaAiResWidth = %f",self.aiResWidth);
CGSize maxSize = CGSizeMake(self.aiResWidth, 100000);
// 1.字符串转data
NSData *data = [self.body dataUsingEncoding:NSUTF8StringEncoding];
// 2. 渲染成 NSAttributedString
CMDocument *doc = [[CMDocument alloc] initWithData:data options:CMDocumentOptionsSmart];
// 3. 创建属性对象
CMTextAttributes *attrs = [[CMTextAttributes alloc] init];
[attrs addStringAttributes:@{NSFontAttributeName:kFont14} forElementWithKinds:CMElementKindAnyHeader];
[attrs addStringAttributes:@{NSFontAttributeName:kFont13} forElementWithKinds:CMElementKindParagraph];
[attrs addStringAttributes:@{NSFontAttributeName:kFont13} forElementWithKinds:CMElementKindText];
CMAttributedStringRenderer *renderer = [[CMAttributedStringRenderer alloc] initWithDocument:doc
attributes:attrs];
NSAttributedString *attrStr = [renderer render];
[self setAttrStr:attrStr];
// 4. 计算高度,给定最大宽度(例如 tableView 的 contentWidth)
CGRect boundingRect = [attrStr boundingRectWithSize:maxSize
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
self.aiResHeight = ceil(boundingRect.size.height);
下面是关键代码,使用UITextView进行渲染
- (UITextView *)body {
if (!_body) {
CGRect rect = CGRectMake(16, 10, 197, 80);
_body = [[UITextView alloc] initWithFrame:rect];
_body.font = kFont13;
_body.textColor = kBlackColorD;
_body.editable = NO;
_body.scrollEnabled = NO; // 如果外层有 UIScrollView/UITableView 就关掉
_body.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0);// 去掉上下默认8pt边距
_body.textContainer.lineFragmentPadding = 0; // 去掉左右 5 pt 的边距
[_body setContentCompressionResistancePriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisVertical];
}
return _body;
}
// 赋值显示
self.body.attributedText = att.attrStr;
// 设置位置
self.body.frame = CGRectMake(16, 12, att.aiResWidth, att.aiResHeight);
注:去掉边距比较重要, 不然显示可能会少一行。