• iOS开发中的Markdown渲染


    iOS开发中的Markdown渲染

    BearyChat的消息是全面支持Markdown语法的,所以在开发BearyChat的iOS客户端的时候需要处理Markdown的渲染。

    主要是两套实现方案:

    1. 直接将Markdown文本转换成NSAttributedString
    2. 先将Markdown文本转换成HTML,再将HTML转换成NSAttributedString

    方案1可用的第三方库有:AttributedMarkdown,这个库是基于C语言的peg-markdown的封装,经过试验发现对GitHub Flavored Markdown支持的不太好。

    方案2可用的第三方库相对多一些:

    将Markdown文本转换成HTML可用的第三方库有:MMMarkdownGHMarkdownParser。其中GHMarkdownParserGitHub Flavored Markdown支持比较好。

    将HTML转换成NSAttributedString,在iOS 7之后UIKitNSAttributedString增加了initWithData:options:documentAttributes:error:方法可以直接转换:









    但是实测发现,这个方法的计算速度非常慢!google了一下,貌似因为这个方法渲染的过程是需要初始化ScriptCore的,每次渲染都要初始化一个ScriptCore肯定是不能忍的。
    第三方库的替代方案:DTCoreTextNSAttributedString-DDHTML。二者之中,DTCoreText是一个比较成熟的第三方库,对样式的控制也比较灵活。

    所以最终选择的方案是:首先用GHMarkdownParser讲Markdown转换成HTML,之后再用DTCoreText讲HTML转换成NSAttributedString最后交给UILabel等控件渲染。
    最终的实现代码就比较简单了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    #import <GHMarkdownParser/GHMarkdownParser.h>
    #import <DTCoreText/DTCoreText.h>

    @interface MarkdownParser
    @property GHMarkdownParser *htmlParser;
    @property (nonatomic, copy) NSDictionary *DTCoreText_options;
    - (NSAttributedString *)DTCoreText_attributedStringFromMarkdown:(NSString *)text;
    @end

    @implementation MarkdownParser

    - (instancetype)init {
    self = [super init];
    if (self) {
    _htmlParser = [[GHMarkdownParser alloc] init];
    _htmlParser.options = kGHMarkdownAutoLink;
    _htmlParser.githubFlavored = YES;
    }
    return self;
    }

    - (NSString *)htmlFromMarkdown:(NSString *)text {
    return [self.htmlParser HTMLStringFromMarkdownString:text];
    }

    - (NSAttributedString *)attributedStringFromMarkdown:(NSString *)text {
    NSString *html = [self htmlFromMarkdown:text];
    NSData *data = [html dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableAttributedString *attributed = [[NSMutableAttributedString alloc] initWithHTMLData:data options:self.DTCoreText_options documentAttributes:nil];
    return attributed;
    }

    - (NSDictionary *)DTCoreText_options {
    if (!_DTCoreText_options) {
    _DTCoreText_options = @{
    DTUseiOS6Attributes:@YES,
    DTIgnoreInlineStylesOption:@YES,
    DTDefaultLinkDecoration:@NO,
    DTDefaultLinkColor:[UIColor blueColor],
    DTLinkHighlightColorAttribute:[UIColor redColor],
    DTDefaultFontSize:@15,
    DTDefaultFontFamily:@"Helvetica Neue",
    DTDefaultFontName:@"HelveticaNeue-Light"
    };
    }
    return _DTCoreText_options;
    }

    @end

    到这里,绝大部分的问题都解决了,还有一点点小问题:把解析得到的NSAttributedString丢给UILabelattributedString渲染的时候,在options里设置的链接的颜色是无效的,貌似UILabel对链接的渲染颜色是不可改的。继续寻找替代方案:用第三方的TTTAttributedLabel代替UILabel。TTTAttributedLabelUILabel的派生类,为UILabel提供了更多对NSAttributedString的控制。通过为TTTAttributedLabel设置超链接的样式最终解决了Markdown渲染的相关问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58

    #import <UIKit/UIKit.h>
    #import <TTTAttributedLabel/TTTAttributedLabel.h>

    @interface MarkdownLabel : TTTAttributedLabel <TTTAttributedLabelDelegate>
    - (void)setDisplayedAttributedString:(id)text;
    @end

    @implementation MarkdownLabel

    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
    [self commonConfig];
    }
    return self;
    }

    - (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
    [self commonConfig];
    }
    return self;
    }

    - (void)commonConfig {
    self.delegate = self;
    NSDictionary *linkAttributes = @{
    (id)kCTForegroundColorAttributeName:[UIColor blueColor],
    NSUnderlineStyleAttributeName:@(kCTUnderlineStyleNone),
    NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-Light" size:15]
    };
    self.linkAttributes = linkAttributes;
    self.enabledTextCheckingTypes = 0;
    }

    - (void)setDisplayedAttributedString:(id)text {
    NSMutableArray *linksAndRange = [@[] mutableCopy];
    [self setText:[text string] afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
    [text enumerateAttributesInRange:NSMakeRange(0, [text length])
    options:0
    usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
    if (attrs[NSLinkAttributeName]) {
    [linksAndRange addObject:@[attrs[NSLinkAttributeName], [NSValue valueWithRange:range]]];
    } else {
    [mutableAttributedString addAttributes:attrs range:range];
    }
    }];
    return mutableAttributedString;
    }];

    for (NSArray *pair in linksAndRange) {
    [self addLinkToURL:pair[0] withRange:[pair[1] rangeValue]];
    }
    }

    @end

    http://nightfade.github.io/2015/06/26/ios-markdown-rendering/

  • 相关阅读:
    历史上的今天:3月1日
    用Windows Live Writer远程更新wordpress博客
    二月只有28天
    办公也可云概念
    FLASH做的画图板
    FLASH鼠标跟随特效
    silverlight应该以什么面孔见人?
    飞信Fetion 开发资料及下载
    收藏一个数学的C++算法的好博客
    下载网站资源共享
  • 原文地址:https://www.cnblogs.com/feng9exe/p/10321109.html
Copyright © 2020-2023  润新知