Swift: wyświetlaj dane HTML w etykiecie lub textView

86

Mam trochę danych HTML, które zawierają nagłówki, akapity, obrazy i listy tagów.

Czy istnieje sposób, aby wyświetlić te dane w jednym UITextViewlub UILabel?

Talha Ahmad Khan
źródło
1
Użyj UIWebView zamiast UITextView lub UILabel. Więc wyświetli się z obrazami
Tyson Vignesh
Tak, myślę, że masz rację @TysonVignesh
Talha Ahmad Khan
@TysonVignesh Jak mogę używać UIWebView do wyświetlania html?
Mohamed Ezzat,
2
@MohamedEzzat zobacz ten link hackingwithswift.com/example-code/uikit/…
Talha Ahmad Khan

Odpowiedzi:

215

Dla Swift 5:

extension String {
    var htmlToAttributedString: NSAttributedString? {
        guard let data = data(using: .utf8) else { return nil }
        do {
            return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
        } catch {
            return nil
        }
    }
    var htmlToString: String {
        return htmlToAttributedString?.string ?? ""
    }
}

Następnie, gdy chcesz umieścić tekst HTML w UITextView, użyj:

textView.attributedText = htmlText.htmlToAttributedString
Roger Carvalho
źródło
6
To zadziałało świetnie, ale zamiast tego musiałem użyć label.attributedText.
Brent Wagoner,
Świetny! Musiałem tylko zmienić dane kodowania na Unicode, dla wschodnioeuropejskich liter łacińskich.
nja
Świetny! ale label.attributedText powinno być label.text podczas dzwonienia
Sazzad Hissain Khan
6
czy ma to zachowywać obrazy?
daredevil1234
1
@Roger Carvalho: Czy istnieje sposób na ustawienie rodziny czcionek, rozmiaru -rozmiaru itp. Dla zawartych tagów HTML?
Bernhard Engl
35

Oto wersja Swift 3:

private func getHtmlLabel(text: String) -> UILabel {
    let label = UILabel()
    label.numberOfLines = 0
    label.lineBreakMode = .byWordWrapping
    label.attributedString = stringFromHtml(string: text)
    return label
}

private func stringFromHtml(string: String) -> NSAttributedString? {
    do {
        let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
        if let d = data {
            let str = try NSAttributedString(data: d,
                                             options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
                                             documentAttributes: nil)
            return str
        }
    } catch {
    }
    return nil
}

Znalazłem tutaj problemy z niektórymi innymi odpowiedziami i trochę mi zajęło, aby to naprawić. Ustawiłem tryb łamania wiersza i liczbę wierszy tak, aby rozmiar etykiety był odpowiedni, gdy HTML obejmował wiele wierszy.

garie
źródło
Kod HTML został przeanalizowany ... ale nieprawidłowo. Tagi już się nie pojawiają, ale pogrubiony tekst nie jest wyświetlany. Nie wiem, które tagi są obsługiwane, może <b>nie.
Pablo
Pogrubione tagi działają dobrze dla mnie. Czy możesz opublikować pełny kod HTML, który nie działa? Może czcionka, której używasz, nie jest dobrze pogrubiona.
garie
HTML to zwykły tekst z edytora CMS, zakodowany tak, aby zwracał ciąg JSON. Aplikacja uzyskuje dostęp do serwisu internetowego, pobiera JSON, który zawiera ten konkretny obiekt tekstowy - wymaganiem od klienta jest tutaj możliwość dodawania tagów html do tekstu, podobnie jak w CMS (wordpress) strony. Może niepoprawnie koduję zwrot? Kiedy parsuję JSON, drukuję ciąg znaków zwrotny podczas debugowania i pojawia się poprawnie, łącznie z '<b> </b>', ale zarówno w emulatorze, jak i urządzeniu do testów, tagi nie będą działać. Używam Swift 3.
Pablo
3
Jak mogę dodać niestandardową czcionkę?
Bhavin Ramani
14

Dodaj to rozszerzenie, aby przekonwertować kod HTML na zwykły ciąg:

    extension String {

        var html2AttributedString: NSAttributedString? {
            guard
                let data = dataUsingEncoding(NSUTF8StringEncoding)
            else { return nil }
            do {
                return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil)
            } catch let error as NSError {
                print(error.localizedDescription)
                return  nil
            }
        }
        var html2String: String {
            return html2AttributedString?.string ?? ""
        }
}

Następnie pokazujesz swój ciąg wewnątrz UITextView lub UILabel

textView.text = yourString.html2String lub

label.text = yourString.html2String
Himanshu
źródło
1
Tak, ale działa tylko w przypadku tekstu w HTML. Martwiły mnie również zdjęcia i listy. Czy istnieje sposób, aby wyświetlić obrazy i listy za pomocą pojedynczego obiektu?
Talha Ahmad Khan
@TalhaAhmadKhan możesz bezpośrednio użyć UIWebView, jeśli masz obrazy. TextView lub etykiety nie zadziałają, jak wiesz.
Sathe_Nagaraja
8

Po tym miałem problemy ze zmianą atrybutów tekstu i widziałem, jak inni pytają dlaczego ...

Dlatego najlepszą odpowiedzią jest użycie rozszerzenia z NSMutableAttributedString:

extension String {

 var htmlToAttributedString: NSMutableAttributedString? {
    guard let data = data(using: .utf8) else { return nil }
    do {
        return try NSMutableAttributedString(data: data,
                                      options: [.documentType: NSMutableAttributedString.DocumentType.html,
                                                .characterEncoding: String.Encoding.utf8.rawValue],
                                      documentAttributes: nil)
    } catch let error as NSError {
        print(error.localizedDescription)
        return  nil
    }
 }

}

A potem możesz to wykorzystać w ten sposób:

if let labelTextFormatted = text.htmlToAttributedString {
                let textAttributes = [
                    NSAttributedStringKey.foregroundColor: UIColor.white,
                    NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 13)
                    ] as [NSAttributedStringKey: Any]
                labelTextFormatted.addAttributes(textAttributes, range: NSRange(location: 0, length: labelTextFormatted.length))
                self.contentText.attributedText = labelTextFormatted
            }
Kassy Barb
źródło
Chcę osiągnąć to samo, ale powyższy kod nie działa.
Pratyush Pratik
7

Swift 3.0

var attrStr = try! NSAttributedString(
        data: "<b><i>text</i></b>".data(using: String.Encoding.unicode, allowLossyConversion: true)!,
        options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil)
label.attributedText = attrStr
Ved Rauniyar
źródło
6

Używam tego:

extension UILabel {
    func setHTML(html: String) {
        do {
            let attributedString: NSAttributedString = try NSAttributedString(data: html.data(using: .utf8)!, options: [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType], documentAttributes: nil)
            self.attributedText = attributedString
        } catch {
            self.text = html
        }
    }
}
Nikolay Khramchenko
źródło
1
To jest dobre, ale będzie miało zastosowanie tylko do UILabel. Byłoby znacznie lepiej, gdyby było to ogólne rozszerzenie, które powinno pobierać html i konwertować na tekst z atrybutami.
i.AsifNoor
4

Szybki 3

extension String {


var html2AttributedString: NSAttributedString? {
    guard
        let data = data(using: String.Encoding.utf8)
        else { return nil }
    do {
        return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:String.Encoding.utf8], documentAttributes: nil)
    } catch let error as NSError {
        print(error.localizedDescription)
        return  nil
    }
}
var html2String: String {
    return html2AttributedString?.string ?? ""
 }
}
Alex Morel
źródło
1
swift 3.1 NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue
Can Aksoy
4

Szybki 5

extension UIColor {
    var hexString: String {
        let components = cgColor.components
        let r: CGFloat = components?[0] ?? 0.0
        let g: CGFloat = components?[1] ?? 0.0
        let b: CGFloat = components?[2] ?? 0.0

        let hexString = String(format: "#%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)),
                               lroundf(Float(b * 255)))

        return hexString
    }
}
extension String {
    func htmlAttributed(family: String?, size: CGFloat, color: UIColor) -> NSAttributedString? {
        do {
            let htmlCSSString = "<style>" +
                "html *" +
                "{" +
                "font-size: \(size)pt !important;" +
                "color: #\(color.hexString) !important;" +
                "font-family: \(family ?? "Helvetica"), Helvetica !important;" +
            "}</style> \(self)"

            guard let data = htmlCSSString.data(using: String.Encoding.utf8) else {
                return nil
            }

            return try NSAttributedString(data: data,
                                          options: [.documentType: NSAttributedString.DocumentType.html,
                                                    .characterEncoding: String.Encoding.utf8.rawValue],
                                          documentAttributes: nil)
        } catch {
            print("error: ", error)
            return nil
        }
    }
}

I na koniec możesz stworzyć UILabel:

func createHtmlLabel(with html: String) -> UILabel {
    let htmlMock = """
    <b>hello</b>, <i>world</i>
    """

    let descriprionLabel = UILabel()
    descriprionLabel.attributedText = htmlMock.htmlAttributed(family: "YourFontFamily", size: 15, color: .red)

    return descriprionLabel
}

Wynik:

wprowadź opis obrazu tutaj

Zobacz tutorial:

https://medium.com/@valv0/a-swift-extension-for-string-and-html-8cfb7477a510

oscarr
źródło
3

W przypadku Swift 5 może również ładować css.

extension String {
    public var convertHtmlToNSAttributedString: NSAttributedString? {
        guard let data = data(using: .utf8) else {
            return nil
        }
        do {
            return try NSAttributedString(data: data,options: [.documentType: NSAttributedString.DocumentType.html,.characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
        }
        catch {
            print(error.localizedDescription)
            return nil
        }
    }

    public func convertHtmlToAttributedStringWithCSS(font: UIFont? , csscolor: String , lineheight: Int, csstextalign: String) -> NSAttributedString? {
        guard let font = font else {
            return convertHtmlToNSAttributedString
        }
        let modifiedString = "<style>body{font-family: '\(font.fontName)'; font-size:\(font.pointSize)px; color: \(csscolor); line-height: \(lineheight)px; text-align: \(csstextalign); }</style>\(self)";
        guard let data = modifiedString.data(using: .utf8) else {
            return nil
        }
        do {
            return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
        }
        catch {
            print(error)
            return nil
        }
    }
}

Następnie przejdź do ciągu, który chcesz przekonwertować na NSAttributedString i umieść go tak, jak w przykładzie poniżej:

myUILabel.attributedText = "Swift is awesome&#33;&#33;&#33;".convertHtmlToAttributedStringWithCSS(font: UIFont(name: "Arial", size: 16), csscolor: "black", lineheight: 5, csstextalign: "center")

wprowadź opis obrazu tutaj Oto, co przyjmuje każdy parametr:

  • czcionka: dodaj swoją czcionkę tak jak zwykle w UILabel / UITextView, używając UIFont z nazwą własnej czcionki i rozmiarem.
  • csscolor: Dodaj kolor w formacie HEX, na przykład „# 000000”, lub użyj nazwy koloru, na przykład „czarny”.
  • lineheight: Jest to odstęp między wierszami, gdy masz wiele wierszy w UILabel / UITextView.
  • csstextalign: To wyrównanie tekstu, wartość, którą musisz dodać, to „left”, „right”, „center” lub „justify”

Źródła: https://johncodeos.com/how-to-display-html-in-uitextview-uilabel-with-custom-color-font-etc-in-ios-using-swift/

Zgpeace
źródło
2

Spróbuj tego:

let label : UILable! = String.stringFromHTML("html String")

func stringFromHTML( string: String?) -> String
    {
        do{
            let str = try NSAttributedString(data:string!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true
                )!, options:[NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSNumber(unsignedLong: NSUTF8StringEncoding)], documentAttributes: nil)
            return str.string
        } catch
        {
            print("html error\n",error)
        }
        return ""
    }

Mam nadzieję, że to pomocne.

Iyyappan Ravi
źródło
Tak, ale działa tylko w przypadku tekstu w HTML. Martwiły mnie również zdjęcia i listy. Czy istnieje sposób, aby wyświetlić obrazy i listy za pomocą pojedynczego obiektu?
Talha Ahmad Khan
3
Należy zauważyć, że używanie NSHTMLTextDocumentTypejest niezwykle powolne [1]. Spróbuj zamiast tego użyć biblioteki takiej jak DDHTML . [1] robpeck.com/2015/04/nshtmltextdocumenttype-is-slow
Christopher Kevin Howell
2

Dzięki za powyższą odpowiedź tutaj jest Swift 4.2


extension String {

    var htmlToAttributedString: NSAttributedString? {
        guard
            let data = self.data(using: .utf8)
            else { return nil }
        do {
            return try NSAttributedString(data: data, options: [
                NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
                NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue
                ], documentAttributes: nil)
        } catch let error as NSError {
            print(error.localizedDescription)
            return  nil
        }
    }

    var htmlToString: String {
        return htmlToAttributedString?.string ?? ""
    }
}
Stephen Chen
źródło
1

Jeśli chcesz HTML, z obrazami i listą, nie jest to obsługiwane przez UILabel. Jednak odkryłem, że YYText załatwia sprawę .

Christopher Kevin Howell
źródło
Jest obsługiwany, jeśli poprawnie zakodujesz ciąg. Gdzieś
kręci się
1

Wyświetlanie obrazów i akapitów tekstu nie jest możliwe w a UITextViewlub UILabel, w tym celu, musisz użyć aUIWebView .

Po prostu dodaj element do serii ujęć, połącz z kodem i wywołaj go, aby załadować adres URL.

OBJ-C

NSString *fullURL = @"http://conecode.com";
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[_viewWeb loadRequest:requestObj];

Szybki

let url = NSURL (string: "http://www.sourcefreeze.com");
let requestObj = NSURLRequest(URL: url!);
viewWeb.loadRequest(requestObj);

Samouczek krok po kroku. http://sourcefreeze.com/uiwebview-example-using-swift-in-ios/

Ulisses
źródło
Jest to możliwe w obu. Ciąg musi być tylko poprawnie zakodowany
froggomad
1

Szybki 5

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: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
            documentAttributes: nil) else { return nil }
        return html
    }
}

Połączenie:

myLabel.attributedText = "myString".htmlAttributedString()
Álvaro Agüero
źródło
0

Wiem, że będzie to wyglądało trochę przesadnie, ale ... Ten kod doda obsługę HTML do UILabel, UITextView, UIButton i możesz łatwo dodać tę obsługę do dowolnego widoku, który ma przypisaną obsługę ciągów:

public protocol CSHasAttributedTextProtocol: AnyObject {
    func attributedText() -> NSAttributedString?
    func attributed(text: NSAttributedString?) -> Self
}

extension UIButton: CSHasAttributedTextProtocol {
    public func attributedText() -> NSAttributedString? {
        attributedTitle(for: .normal)
    }

    public func attributed(text: NSAttributedString?) -> Self {
        setAttributedTitle(text, for: .normal); return self
    }
}

extension UITextView: CSHasAttributedTextProtocol {
    public func attributedText() -> NSAttributedString? { attributedText }

    public func attributed(text: NSAttributedString?) -> Self { attributedText = text; return self }
}

extension UILabel: CSHasAttributedTextProtocol {
    public func attributedText() -> NSAttributedString? { attributedText }

    public func attributed(text: NSAttributedString?) -> Self { attributedText = text; return self }
}

public extension CSHasAttributedTextProtocol
        where Self: CSHasFontProtocol, Self: CSHasTextColorProtocol {
    @discardableResult
    func html(_ text: String) -> Self { html(text: text) }

    @discardableResult
    func html(text: String) -> Self {
        let html = """
                   <html><body style="color:\(textColor!.hexValue()!); 
                                font-family:\(font()!.fontName); 
                                font-size:\(font()!.pointSize);">\(text)</body></html>
                   """
        html.data(using: .unicode, allowLossyConversion: true).notNil { data in
            attributed(text: try? NSAttributedString(data: data, options: [
                .documentType: NSAttributedString.DocumentType.html,
                .characterEncoding: NSNumber(value: String.Encoding.utf8.rawValue)
            ], documentAttributes: nil))
        }
        return self
    }
}


public protocol CSHasFontProtocol: AnyObject {
    func font() -> UIFont?
    func font(_ font: UIFont?) -> Self
}

extension UIButton: CSHasFontProtocol {
    public func font() -> UIFont? { titleLabel?.font }

    public func font(_ font: UIFont?) -> Self { titleLabel?.font = font; return self }
}

extension UITextView: CSHasFontProtocol {
    public func font() -> UIFont? { font }

    public func font(_ font: UIFont?) -> Self { self.font = font; return self }
}

extension UILabel: CSHasFontProtocol {
    public func font() -> UIFont? { font }

    public func font(_ font: UIFont?) -> Self { self.font = font; return self }
}

public protocol CSHasTextColorProtocol: AnyObject {
    func textColor() -> UIColor?
    func text(color: UIColor?) -> Self
}

extension UIButton: CSHasTextColorProtocol {
    public func textColor() -> UIColor? { titleColor(for: .normal) }

    public func text(color: UIColor?) -> Self { setTitleColor(color, for: .normal); return self }
}

extension UITextView: CSHasTextColorProtocol {
    public func textColor() -> UIColor? { textColor }

    public func text(color: UIColor?) -> Self { textColor = color; return self }
}

extension UILabel: CSHasTextColorProtocol {
    public func textColor() -> UIColor? { textColor }

    public func text(color: UIColor?) -> Self { textColor = color; return self }
}
Renetik
źródło
-1

JEŚLI MASZ STRONĘ Z KODEM HTML, MOŻESZ UŻYĆ:

extension String {
var utfData: Data? {
        return self.data(using: .utf8)
    }

    var htmlAttributedString: NSAttributedString? {
        guard let data = self.utfData else {
            return nil
        }
        do {
            return try NSAttributedString(data: data,
                                          options: [
                                            .documentType: NSAttributedString.DocumentType.html,
                                            .characterEncoding: String.Encoding.utf8.rawValue
                ], documentAttributes: nil)
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }

    var htmlString: String {
        return htmlAttributedString?.string ?? self 
    }
}

I W SWOIM KODZIE UŻYWASZ:

label.text = "something".htmlString
Pedro Menezes
źródło