Конвертировать HTML в NSAttributedString в iOS - PullRequest
140 голосов
/ 18 ноября 2010

Я использую экземпляр UIWebView для обработки некоторого текста и его правильного цвета, он дает результат в виде HTML, но вместо того, чтобы отображать его в UIWebView Я хочу отобразить его, используя Core Text с NSAttributedString.

Я могу создать и нарисовать NSAttributedString, но я не уверен, как можно преобразовать и отобразить HTML-код в приписанную строку.

Я понимаю, что под Mac OS X NSAttributedStringесть метод initWithHTML:, но это было добавление только для Mac и недоступно для iOS.

Я также знаю, что на этот вопрос есть похожий вопрос, но на него не было ответов, хотя я бы попробовал еще раз ипосмотрите, создал ли кто-нибудь способ сделать это, и если да, то если бы он мог поделиться им.

Ответы [ 14 ]

275 голосов
/ 19 сентября 2013

В iOS 7 UIKit добавил initWithData: options: documentAttributes: error: метод, который может инициализировать NSAtttributedString с использованием HTML, например:

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

В 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)
42 голосов
/ 11 января 2011

Идет незавершенное добавление с открытым исходным кодом к NSAttributedString Оливером Дробником из Github.Он использует NSScanner для разбора HTML.

23 голосов
/ 10 декабря 2015

Создание NSAttributedString из HTML должно быть сделано в главном потоке!

Обновление: оказывается, что рендеринг HTML NSAttributedString зависит от WebKit под капотом, и должен запускаться в главном потоке , иначе это может вызвать сбой приложения с SIGTRAP .

Новый журнал ошибок Relic:

enter image description here

Ниже приведено обновленное Потоковое Расширение 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)
            }
        }
    }
}

Использование:

let html = "<center>Here is some <b>HTML</b></center>"
html.attributedStringFromHTML { attString in
    self.bodyLabel.attributedText = attString
}

Выход:

enter image description here

16 голосов
/ 06 марта 2017

Расширение инициализатора Swift для NSAttributedString

Я хотел добавить это как расширение к NSAttributedString, а не String. Я попробовал это как статическое расширение и инициализатор. Я предпочитаю инициализатор, который я включил ниже.

Swift 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)
}

Swift 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)
8 голосов
/ 25 мая 2016

Это расширение 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
    }
}

Для использования,

label.attributedText = "<b>Hello</b> \u{2022} babe".htmlAttributedString()

В приведенном выше, я имеюнамеренно добавил юникод \ u2022, чтобы показать, что он правильно отображает юникод.

Тривиальное: кодировка по умолчанию, используемая NSAttributedString, - NSUTF16StringEncoding (не UTF8!).

5 голосов
/ 30 ноября 2017

Swift 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!")
5 голосов
/ 28 сентября 2016

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
}
4 голосов
/ 07 января 2017

Внесены некоторые изменения в решение Эндрю и обновлен код до 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)
            }
        }
    }
}

Пример использования:

mainTextView.setAttributedStringFromHTML("<i>Hello world!</i>") { _ in }
4 голосов
/ 18 ноября 2010

Единственное решение, которое у вас есть сейчас, - это анализ HTML, создание некоторых узлов с заданными атрибутами point / font / etc, а затем объединение их вместе в NSAttributedString. Это большая работа, но если все сделано правильно, в будущем ее можно будет использовать повторно.

2 голосов
/ 27 февраля 2017

Swift 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()
...