it-swarm.com.de

Konvertieren Sie HTML in NSAttributedString in iOS

Ich verwende eine Instanz von UIWebView, um Text zu verarbeiten und korrekt zu färben. Das Ergebnis wird als HTML angezeigt. Statt es in UIWebView anzuzeigen, möchte ich es mit Core Text mit einer NSAttributedString anzeigen. 

Ich bin in der Lage, die Variable NSAttributedString zu erstellen und zu zeichnen, aber ich bin mir nicht sicher, wie ich den HTML-Code in den attributierten String konvertieren und zuordnen kann.

Ich verstehe, dass NSAttributedString unter Mac OS X eine initWithHTML:-Methode hat, dies war jedoch nur ein Mac-Zusatz und ist für iOS nicht verfügbar.

Ich weiß auch, dass es eine ähnliche Frage gibt, aber es gab keine Antworten. Ich würde zwar noch einmal versuchen, zu sehen, ob jemand einen Weg dafür geschaffen hat und wenn ja, ob er es teilen könnte.

135
Joshua

In iOS 7 fügte UIKit eine initWithData: options: documentAttributes: Fehler: -Methode hinzu, die einen NSAtttributedString mithilfe von HTML initialisieren kann, z.

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

In 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)
268
pix

Es gibt einen Work-in-Progress Open Source-Zusatz zu NSAttributedString von Oliver Drobnik bei Github. Es verwendet NSScanner für die HTML-Analyse.

42
Ingve

Das Erstellen eines NSAttributedString aus HTML muss im Hauptthread erfolgen!

Update: Es stellt sich heraus, dass das HTML-Rendering von NSAttributedString von WebKit abhängig ist und auf dem Haupt-Thread ausgeführt werden muss oder es wird gelegentlich ausgeführt stürze die App mit einem SIGTRAP ab.

Neues Relikt-Absturzprotokoll:

enter image description here

Unten ist eine aktualisierte thread-sichere Swift 2 String-Erweiterung:

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

Verwendungszweck:

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

Ausgabe:

enter image description here

24

Swift-Initialisierungserweiterung für NSAttributedString

Meine Neigung bestand darin, dies als Erweiterung zu NSAttributedString statt zu String hinzuzufügen. Ich habe es als statische Erweiterung und als Initialisierer versucht. Ich bevorzuge den Initialisierer, den ich unten aufgeführt habe.

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

Beispiel

let html = "<b>Hello World!</b>"
let attributedString = NSAttributedString(html: html)
15
Mobile Dan

Dies ist eine String-Erweiterung, die in Swift geschrieben wurde, um einen HTML-String als NSAttributedString zurückzugeben.

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

Benutzen, 

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

Im obigen Abschnitt habe ich absichtlich einen Unicode hinzugefügt, um zu zeigen, dass Unicode richtig dargestellt wird. 

Eine triviale: Die Standardkodierung, die NSAttributedString verwendet, ist NSUTF16StringEncoding (nicht UTF8!).

7
samwize

Swift 4


  • NSAttributedString Bequemlichkeitsinitialisierer
  • Ohne zusätzliche Wachen
  • wirft Fehler

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

}

Verwendungszweck

UILabel.attributedText = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!")
5
AamirR

Swift 3.0 Xcode 8 Version

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
}
5
fssilva

Änderungen an der Lösung von Andrew vorgenommen und der Code auf Swift 3 aktualisiert:

Dieser Code verwendet jetzt UITextView als self und kann die ursprüngliche Schriftart, Schriftgröße und Textfarbe übernehmen

Hinweis: toHexString() ist Erweiterung von hier

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

Verwendungsbeispiel:

mainTextView.setAttributedStringFromHTML("<i>Hello world!</i>") { _ in }
4

Die einzige Lösung, die Sie jetzt haben, besteht darin, den HTML-Code zu analysieren, einige Knoten mit den angegebenen Punkt-/font-/etc-Attributen aufzubauen und sie dann zu einem NSAttributedString zusammenzufassen. Es ist viel Arbeit, aber wenn es richtig gemacht wird, kann es in Zukunft wiederverwendbar sein.

4
jer

Die obige Lösung ist richtig. 

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

Aber die App stürzt ab, wenn Sie es auf iOS 8.1.2 oder 3 ausführen.

Um den Absturz zu vermeiden, kannst du Folgendes tun: in einer Warteschlange ausführen. Damit es immer am Hauptthread liegt.

2

Swift 3 :
Versuche dies

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

Und zur Verwendung von: 

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()
2
reza_khalafi

Die Verwendung von NSHTMLTextDocumentType ist langsam und es ist schwierig, Stile zu steuern. Ich schlage vor, Sie sollten meine Bibliothek ausprobieren, die Atributika heißt. Es hat einen eigenen sehr schnellen HTML-Parser. Sie können auch beliebige Tag-Namen haben und für sie einen beliebigen Stil definieren.

Beispiel:

let str = "<strong>Hello</strong> World!".style(tags:
    Style("strong").font(.boldSystemFont(ofSize: 15))).attributedString

label.attributedText = str

Sie finden es hier https://github.com/psharanda/Atributika

2
Pavel Sharanda

mit schrift

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

alternativ können Sie die Versionen verwenden, von denen diese abgeleitet wurden, und die Schriftart in UILabel festlegen, nachdem attributedString festgelegt wurde

0
Anton Tropashko

Hilfreiche Erweiterungen

Inspiriert von diesem Thread, einem Pod und dem ObjC-Beispiel von Erica Sadun in iOS Gourmet Cookbook, S. 80, schrieb ich eine Erweiterung zu String und zu NSAttributedString, um zwischen HTML-Klammern und NSAttributedStrings hin und her zu wechseln - auf GitHub hier , was ich hilfreich gefunden habe.

Die signaturen sind (wieder vollständiger Code in einer Gist, Link oben):

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 }
0
AmitaiB