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?

Talha Ahmad Khan
fuente
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
2
@MohamedEzzat ver este enlace hackingwithswift.com/example-code/uikit/…
Talha Ahmad Khan

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
Roger Carvalho
fuente
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.

garie
fuente
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
Himanshu
fuente
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
            }
Barb kassy
fuente
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
Ved Rauniyar
fuente
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
        }
    }
}
Nikolay Khramchenko
fuente
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 ?? ""
 }
}
Alex Morel
fuente
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

oscarr
fuente
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.

Iyyappan Ravi
fuente
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 ?? ""
    }
}
Stephen Chen
fuente
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/

Zgpeace
fuente
1

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

Christopher Kevin Howell
fuente
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/

Ulises
fuente
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()
Álvaro Agüero
fuente
-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
Pedro Menezes
fuente