在iOS中将HTML转换为NSAttributedString

Jos*_*hua 143 iphone cocoa-touch objective-c nsattributedstring core-text

我正在使用一个实例UIWebView来处理一些文本并正确地着色它,它将结果作为HTML而不是显示在UIWebView我希望Core Text用a 显示它NSAttributedString.

我能够创建和绘制NSAttributedString但我不确定如何将HTML转换并将HTML映射到属性字符串.

据我所知,在Mac OS X下NSAttributedString有一个initWithHTML:方法,但这只是Mac的补充,不适用于iOS.

我也知道有一个类似的问题,但它没有答案,我虽然我会再试一次,看看是否有人创造了一种方法来做到这一点,如果是的话,他们是否可以分享它.

pix*_*pix 281

在iOS 7中,UIKit添加了一个initWithData:options:documentAttributes:error:方法,它可以使用HTML初始化NSAtttributedString,例如:

[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding] 
                                 options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                           NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} 
                      documentAttributes:nil error:nil];
Run Code Online (Sandbox Code Playgroud)

在Swift中:

let htmlData = NSString(string: details).data(using: String.Encoding.unicode.rawValue)
let options = [NSAttributedString.DocumentReadingOptionKey.documentType:
        NSAttributedString.DocumentType.html]
let attributedString = try? NSMutableAttributedString(data: htmlData ?? Data(),
                                                          options: options,
                                                          documentAttributes: nil)
Run Code Online (Sandbox Code Playgroud)

  • 由于某种原因,选项NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType导致编码花了很长时间:( (28认同)
  • 我这样做了,但是在iOS 8上要小心.它的速度很慢,几百个字符接近一秒.(在iOS 7中,它几乎是即时的.) (15认同)
  • 太糟糕了NSHTMLTextDocumentType(字面上)比使用NSRange设置属性慢1000倍.(描述了带有一个粗体标签的短标签.) (13认同)
  • 请注意,如果您想在后台线程中使用它,如果您不能使用此方法NSHTMLTextDocumentType.即使使用ios 7,它也不会将TextKit用于HTML渲染.看看Ingve推荐的DTCoreText库. (6认同)
  • 真棒.只是一个想法,你可能会做[NSNumber numberWithInt:NSUTF8StringEncoding]为@(NSUTF8StringEncoding),不是吗? (2认同)
  • 我也遇到了崩溃问题,因为我没有为主线程上的归属字符串做initWithData (2认同)
  • 警告任何考虑此解决方案的人:此 API 受到诅咒,将在您的应用程序中释放 Zalgo。(https://blog.izs.me/2013/08/designing-apis-for-asynchrony) 该 API *在返回之前*执行主运行循环,这意味着如果您在调用它之前在主队列上放置一个块,那么块可能会在返回之前执行。这里有一个很好的解释:/sf/ask/3930837921/ 如果您使用此 API,祝您推理代码好运! (2认同)

Ing*_*gve 43

Github的Oliver Drobnik正在对NSAttributedString进行一项正在进行的开源添加.它使用NSScanner进行HTML解析.

  • @Lirik Overkill对你来说可能对其他人来说很完美,也就是说你的评论对你来说没有多大帮助. (3认同)
  • 请注意,此项目要求是开源的,并由标准的2条款BSD许可证涵盖.这意味着您必须提及Cocoanetics作为此代码的原始作者,并在您的应用程序中重现LICENSE文本. (3认同)

And*_*ber 27

从HTML创建NSAttributedString必须在主线程上完成!

更新:事实证明,NSAttributedString HTML呈现依赖于WebKit,必须在主线程上运行, 否则偶尔会使用SIGTRAP使应用程序崩溃.

新Relic崩溃日志:

在此输入图像描述

下面是一个更新的线程安全的 Swift 2 String扩展:

extension String {
    func attributedStringFromHTML(completionBlock:NSAttributedString? ->()) {
        guard let data = dataUsingEncoding(NSUTF8StringEncoding) else {
            print("Unable to decode data from html string: \(self)")
            return completionBlock(nil)
        }

        let options = [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
                   NSCharacterEncodingDocumentAttribute: NSNumber(unsignedInteger:NSUTF8StringEncoding)]

        dispatch_async(dispatch_get_main_queue()) {
            if let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) {
                completionBlock(attributedString)
            } else {
                print("Unable to create attributed string from html string: \(self)")
                completionBlock(nil)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

let html = "<center>Here is some <b>HTML</b></center>"
html.attributedStringFromHTML { attString in
    self.bodyLabel.attributedText = attString
}
Run Code Online (Sandbox Code Playgroud)

输出:

在此输入图像描述


Mob*_*Dan 19

NSAttributedString上的Swift初始化程序扩展

我倾向于将此作为一个扩展,NSAttributedString而不是String.我尝试将它作为静态扩展和初始化器.我更喜欢初始化器,这是我在下面包含的内容.

斯威夫特4

internal convenience init?(html: String) {
    guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
        return nil
    }

    guard let attributedString = try?  NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) else {
        return nil
    }

    self.init(attributedString: attributedString)
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

extension NSAttributedString {

internal convenience init?(html: String) {
    guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
        return nil
    }

    guard let attributedString = try? NSMutableAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) else {
        return nil
    }

    self.init(attributedString: attributedString)
}
}
Run Code Online (Sandbox Code Playgroud)

let html = "<b>Hello World!</b>"
let attributedString = NSAttributedString(html: html)
Run Code Online (Sandbox Code Playgroud)

  • 您正在使用UTF-8解码数据,但已使用UTF-16对其进行了编码 (2认同)

sam*_*ize 10

这是一个String用Swift编写的扩展,用于返回HTML字符串NSAttributedString.

extension String {
    func htmlAttributedString() -> NSAttributedString? {
        guard let data = self.dataUsingEncoding(NSUTF16StringEncoding, allowLossyConversion: false) else { return nil }
        guard let html = try? NSMutableAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) else { return nil }
        return html
    }
}
Run Code Online (Sandbox Code Playgroud)

要用,

label.attributedText = "<b>Hello</b> \u{2022} babe".htmlAttributedString()
Run Code Online (Sandbox Code Playgroud)

在上面,我特意添加了一个unicode\u2022来显示它正确呈现unicode.

一个小问题:使用的默认编码NSAttributedStringNSUTF16StringEncoding(不是UTF8!).


He *_*何一非 6

Andrew的解决方案进行了一些修改,并将代码更新为 Swift 3:

此代码现在使用 UITextView 作为self并能够继承其原始字体、字体大小和文本颜色

注意:toHexString()是从这里扩展

extension UITextView {
    func setAttributedStringFromHTML(_ htmlCode: String, completionBlock: @escaping (NSAttributedString?) ->()) {
        let inputText = "\(htmlCode)<style>body { font-family: '\((self.font?.fontName)!)'; font-size:\((self.font?.pointSize)!)px; color: \((self.textColor)!.toHexString()); }</style>"

        guard let data = inputText.data(using: String.Encoding.utf16) else {
            print("Unable to decode data from html string: \(self)")
            return completionBlock(nil)
        }

        DispatchQueue.main.async {
            if let attributedString = try? NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) {
                self.attributedText = attributedString
                completionBlock(attributedString)
            } else {
                print("Unable to create attributed string from html string: \(self)")
                completionBlock(nil)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

mainTextView.setAttributedStringFromHTML("<i>Hello world!</i>") { _ in }
Run Code Online (Sandbox Code Playgroud)


fss*_*lva 5

Swift 3.0 Xcode 8版

func htmlAttributedString() -> NSAttributedString? {
    guard let data = self.data(using: String.Encoding.utf16, allowLossyConversion: false) else { return nil }
    guard let html = try? NSMutableAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) else { return nil }
    return html
}
Run Code Online (Sandbox Code Playgroud)


Aam*_*irR 5

斯威夫特4


  • NSAttributedString方便初始化程序
  • 没有额外的警卫
  • 抛出错误

extension NSAttributedString {

    convenience init(htmlString html: String) throws {
        try self.init(data: Data(html.utf8), options: [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ], documentAttributes: nil)
    }

}
Run Code Online (Sandbox Code Playgroud)

用法

UILabel.attributedText = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!")
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

96219 次

最近记录:

5 年,12 月 前