Swift: muestra datos HTML en una etiqueta o textView


83

Tengo algunos datos HTML, que contienen títulos, párrafos, imágenes y listas de etiquetas.

¿Hay alguna forma de mostrar estos datos en uno UITextViewo UILabel?


1
Utilice UIWebView en lugar de UITextView o UILabel. Por lo que se mostrará con imágenes incluidas
Tyson Vignesh

Sí, creo que tienes razón @TysonVignesh
Talha Ahmad Khan

@TysonVignesh ¿Cómo puedo usar UIWebView para mostrar html?
Mohamed Ezzat

Respuestas:


207

Para 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 ?? ""
    }
}

Luego, siempre que desee poner texto HTML en un uso de UITextView:

textView.attributedText = htmlText.htmlToAttributedString

6
Esto funcionó muy bien para mí, pero tuve que usar label.attributedText en su lugar.
Brent Waggoner

¡Excelente! Solo necesitaba cambiar los datos de codificación a Unicode, para letras latinas de Europa del Este.
nja

¡Excelente! pero label.attributedText debe ser label.text al llamar
Sazzad Hissain Khan

6
¿Se supone que esto preserva las imágenes?
daredevil1234

1
@Roger Carvalho: ¿Hay alguna manera de establecer la familia de fuentes, el tamaño, etc. para las etiquetas html contenidas?
Bernhard Engl

35

Aquí hay una versión de 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
}

Encontré problemas con algunas de las otras respuestas aquí y me tomó un poco hacerlo bien. Configuré el modo de salto de línea y el número de líneas para que la etiqueta tenga el tamaño adecuado cuando el HTML abarque varias líneas.


El HTML está analizado ... pero incorrectamente. Las etiquetas ya no aparecen, pero no se muestra el texto en negrita. No sé qué etiquetas son compatibles, tal vez <b>no.
Pablo

Las etiquetas en negrita funcionan bien para mí. ¿Puedes publicar tu html completo que no funciona? Quizás la fuente que estás usando no se muestra bien en negrita.
garie

El html es solo texto de un editor de CMS, codificado para regresar en una cadena JSON. La aplicación accede al servicio web, obtiene el JSON que contiene este objeto de texto específico; el requisito del cliente aquí es la posibilidad de agregar etiquetas html al texto, similar a un CMS (wordpress) de un sitio web. ¿Quizás estoy codificando la devolución incorrectamente? Cuando analizo el JSON, imprimo el retorno de la cadena en la depuración y aparece correctamente, incluido el '<b> </b>', pero tanto en el emulador como en el dispositivo para las pruebas, las etiquetas no funcionan. Estoy usando Swift 3.
Pablo

3
¿Cómo puedo agregar una fuente personalizada?
Bhavin Ramani

14

Agregue esta extensión para convertir su código html en una cadena normal:

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

Y luego muestra su Cadena dentro de un UITextView o UILabel

textView.text = yourString.html2String o

label.text = yourString.html2String

1
Sí, pero solo funciona con texto en HTML. También me preocupaban las imágenes y las listas. ¿Hay alguna forma de mostrar las imágenes y las listas de un solo objeto?
Talha Ahmad Khan

@TalhaAhmadKhan puede usar directamente UIWebView si tiene imágenes. TextView o las etiquetas no funcionarán como sabe.
Sathe_Nagaraja

8

Tuve problemas para cambiar los atributos del texto después de eso, y pude ver a otros preguntando por qué ...

Entonces, la mejor respuesta es usar la extensión con NSMutableAttributedString en su lugar:

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

}

Y luego puedes usarlo de esta manera:

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
            }

Quiero lograr lo mismo, pero el código anterior no funciona.
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

6

Estoy usando esto:

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

1
Esto es bueno, pero solo se aplicará a UILabel. Sería mucho mejor si fuera una extensión genérica que debería tomar html y convertir en texto con atributos.
i.AsifNoor

4

Swift 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 ?? ""
 }
}

1
swift 3.1 NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue
Can Aksoy

3

Rápido 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
        }
    }
}

Y finalmente puedes crear 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
}

Resultado:

ingrese la descripción de la imagen aquí

Ver tutorial:

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


2

Prueba esto:

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

Espero que sea de ayuda.


Sí, pero solo funciona con texto en HTML. También me preocupaban las imágenes y las listas. ¿Hay alguna forma de mostrar las imágenes y las listas de un solo objeto?
Talha Ahmad Khan

3
Cabe señalar que el uso NSHTMLTextDocumentTypees increíblemente lento [1]. Intente utilizar una biblioteca como DDHTML en su lugar. [1] robpeck.com/2015/04/nshtmltextdocumenttype-is-slow
Christopher Kevin Howell

2

Gracias por la respuesta anterior aquí es 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 ?? ""
    }
}

2

Para Swift 5, también puede cargar 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
        }
    }
}

Después de eso, vaya a la cadena que desea convertir a NSAttributedString y colóquela como en el ejemplo siguiente:

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

ingrese la descripción de la imagen aquí Esto es lo que toma cada parámetro:

  • fuente: agregue su fuente como suele hacer en UILabel / UITextView, usando UIFont con el nombre de su fuente personalizada y el tamaño.
  • csscolor: agregue color en formato HEX, como "# 000000" o use el nombre del color, como "negro".
  • lineheight: es el espacio entre las líneas cuando tiene varias líneas en un UILabel / UITextView.
  • csstextalign: es la alineación del texto, el valor que debe agregar es "izquierda" o "derecha" o "centro" o "justificar"

Referencia: https://johncodeos.com/how-to-display-html-in-uitextview-uilabel-with-custom-color-font-etc-in-ios-using-swift/


1

Si desea HTML, con imágenes y una lista, UILabel no lo admite. Sin embargo, he descubierto que YYText hace el truco.


Es compatible si codifica la cadena correctamente. Hay una extensión de
cadena

1

Mostrar imágenes y párrafos de texto no es posible en a UITextViewo UILabel, para esto, debe usar a UIWebView.

Simplemente agregue el elemento en el guión gráfico, enlace a su código y llámelo para cargar la URL.

OBJ-C

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

Rápido

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

Tutorial paso a paso. http://sourcefreeze.com/uiwebview-example-using-swift-in-ios/


Es posible en ambos. La cadena solo necesita codificarse correctamente
froggomad

1

Rápido 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
    }
}

Llamada:

myLabel.attributedText = "myString".htmlAttributedString()

-1

SI TIENE UNA CADENA CON CÓDIGO HTML DENTRO, PUEDE USAR:

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

Y EN SU CÓDIGO UTILIZA:

label.text = "something".htmlString
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.