在 iOS 中将 HTML 转换为 NSAttributedString
-
26-09-2019 - |
题
我正在使用一个实例 UIWebView
为了处理一些文本并正确着色,它以 HTML 形式给出结果,而不是将其显示在 UIWebView
我想使用显示它 Core Text
与一个 NSAttributedString
.
我能够创建和绘制 NSAttributedString
但我不确定如何将 HTML 转换并映射到属性字符串中。
据我了解,在 Mac OS X 下 NSAttributedString
有一个 initWithHTML:
方法,但这只是 Mac 的附加功能,不适用于 iOS。
我也知道有一个类似的问题,但没有答案,我想我会再试一次,看看是否有人创建了一种方法来做到这一点,如果是,他们是否可以分享。
解决方案
在 iOS 7 中,UIKit 添加了一个 initWithData:options:documentAttributes:error:
方法可以初始化一个 NSAtttributedString
使用 HTML,例如:
[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}
documentAttributes:nil error:nil];
在斯威夫特中:
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)
其他提示
有一个工作在进展开源除了NSAttributedString 通过奥利弗Drobnik在Github上。它使用用于NSScanner HTML解析。
创建与HTML的NSAttributedString必须在主线程上完成!
更新:原来,NSAttributedString HTML渲染依赖WebKit的引擎盖下,和必须在主线程上运行 也偶尔会崩溃的应用程序有一个SIGTRAP
新遗物崩溃日志:
下面是一个更新的线程安全强>夫特2字符串延伸:
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)
}
}
}
}
用法:
let html = "<center>Here is some <b>HTML</b></center>"
html.attributedStringFromHTML { attString in
self.bodyLabel.attributedText = attString
}
输出:
夫特初始化扩展上NSAttributedString
我的倾向是添加此作为一个扩展到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)
}
<强>夫特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)
}
}
示例强>
let html = "<b>Hello World!</b>"
let attributedString = NSAttributedString(html: html)
这是一个用一个斯威夫特扩展String
返回一个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
}
}
要使用,
label.attributedText = "<b>Hello</b> \u{2022} babe".htmlAttributedString()
在上文中,我有意添加一个unicode \ U2022,以表明它正确呈现的unicode。
一个微不足道:编码NSAttributedString
使用默认是NSUTF16StringEncoding
(!不UTF8)
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
}
雨燕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)
}
}
用法
UILabel.attributedText = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!")
您现在所拥有的唯一的解决办法是解析HTML,建立与给定的点/字体/等属性一些节点,然后将它们结合在一起成一个NSAttributedString。这是一个大量的工作,但如果做得正确,可以在未来可重复使用的。
提出了一些修改上安德鲁的溶液和代码更新到夫特3:
此代码现在使用的UITextView作为self
和能够继承其原始字体,字体大小和文本颜色
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)
}
}
}
}
用法示例:
mainTextView.setAttributedStringFromHTML("<i>Hello world!</i>") { _ in }
在上述溶液是正确的。
[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}
documentAttributes:nil error:nil];
但是,如果你在iOS 8.1,2或3运行它的应用程序wioll崩溃。
为避免你所能做的就是崩溃:在队列中运行此。因此,它总是在主线程。强>
NSHTMLTextDocumentType的使用是缓慢的,这是很难控制的样式。我建议你试试我的图书馆被称为Atributika。它有自己非常快的HTML解析器。你也可以有任何标记名称和定义任何风格的他们。
示例:
let str = "<strong>Hello</strong> World!".style(tags:
Style("strong").font(.boldSystemFont(ofSize: 15))).attributedString
label.attributedText = str
<强>夫特3 强>:结果 尝试此:
extension String {
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
}
}
和使用:
let str = "<h1>Hello bro</h1><h2>Come On</h2><h3>Go sis</h3><ul><li>ME 1</li><li>ME 2</li></ul> <p>It is me bro , remember please</p>"
self.contentLabel.attributedText = str.htmlAttributedString()
有用的扩展程序
此线程,一个吊舱,并在iOS的美食食谱第80页埃里卡Sadun的ObjC例子启发,我写了一篇关于String
和NSAttributedString
的扩展,来回之间HTML纯字符串和NSAttributedStrings,反之亦然 - 在GitHub rel="nofollow">,我已经发现有益的。
的签名强>是(再次,在一个要点全码,链接以上):
extension NSAttributedString {
func encodedString(ext: DocEXT) -> String?
static func fromEncodedString(_ eString: String, ext: DocEXT) -> NSAttributedString?
static func fromHTML(_ html: String) -> NSAttributedString? // same as above, where ext = .html
}
extension String {
func attributedString(ext: DocEXT) -> NSAttributedString?
}
enum DocEXT: String { case rtfd, rtf, htm, html, txt }
与字体
extension NSAttributedString
{
internal convenience init?(html: String, font: UIFont? = nil) {
guard let data = html.data(using: String.Encoding.utf16, allowLossyConversion: false) else {
return nil
}
assert(Thread.isMainThread)
guard let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) else {
return nil
}
let mutable = NSMutableAttributedString(attributedString: attributedString)
if let font = font {
mutable.addAttribute(.font, value: font, range: NSRange(location: 0, length: mutable.length))
}
self.init(attributedString: mutable)
}
}
可替换地可以使用这是从获得的版本和集 设置后字体上的UILabel attributedString