Swift: отображение данных HTML в метке или текстовом представлении


86

У меня есть некоторые данные HTML, которые содержат заголовки, абзацы, изображения и теги списков.

Есть ли способ отобразить эти данные в одном UITextViewили UILabel?


1
Используйте UIWebView вместо UITextView или UILabel. Таким образом, он будет отображаться, включая изображения
Тайсон Винеш

Да, я думаю, что вы правы @TysonVignesh
Ahmad Khan

@TysonVignesh Как я могу использовать UIWebView для отображения html?
Mohamed Ezzat

2
@MohamedEzzat см. Эту ссылку hackingwithswift.com/example-code/uikit/…
Ahmad Khan

Ответы:


215

Для 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 ?? ""
    }
}

Затем, когда вы хотите поместить текст HTML в UITextView, используйте:

textView.attributedText = htmlText.htmlToAttributedString

6
У меня это отлично сработало, но вместо этого мне пришлось использовать label.attributedText.
Brent Wagoner

Большой! Мне просто нужно было изменить данные кодировки на Unicode для восточноевропейских латинских букв.
nja

Большой! но label.attributedText должен быть label.text при звонке
Sazzad Hissain Khan

6
это должно сохранять изображения?
daredevil1234

1
@ Роджер Карвалью: Есть ли способ установить семейство шрифтов, размер и т. Д. Для содержащихся тегов html?
Бернхард Энгл,

35

Вот версия 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
}

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


HTML проанализирован ... но неправильно. Теги больше не отображаются, но жирный текст не отображается. Я не знаю, какие теги поддерживаются, возможно <b>, нет.
Пабло

Жирные теги мне подходят. Можете ли вы опубликовать полный HTML-код, который не работает? Возможно, шрифт, который вы используете, не выделяется жирным шрифтом.
Garie

HTML - это просто текст из редактора CMS, закодированный для возврата в строке JSON. Приложение обращается к веб-сервису, получает JSON, содержащий этот конкретный текстовый объект - требование со стороны клиента заключается в возможности добавления тегов html к тексту, как в CMS (wordpress) веб-сайта. Может я неправильно кодирую возврат? Когда я разбираю JSON, я печатаю строку return при отладке и отображается правильно, включая «<b> </b>», но и на эмуляторе, и на устройстве для тестов теги не работают. Я использую Swift 3.
Пабло

3
Как я могу добавить собственный шрифт?
Бхавин Рамани

14

Добавьте это расширение, чтобы преобразовать ваш html-код в обычную строку:

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

А затем вы показываете свою строку внутри UITextView или UILabel

textView.text = yourString.html2String или же

label.text = yourString.html2String

1
Да, но это работает только для текста в HTML. Меня также беспокоили изображения и списки. Есть ли способ отображать изображения и списки одним объектом ??
Талха Ахмад Хан

@TalhaAhmadKhan, вы можете напрямую использовать UIWebView, если у вас есть изображения. TextView или метки не будут работать, как вы знаете.
Sathe_Nagaraja

8

После этого у меня возникли проблемы с изменением атрибутов текста, и я мог видеть, как другие спрашивали, почему ...

Поэтому лучший ответ - вместо этого использовать расширение с 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
    }
 }

}

И тогда вы можете использовать это так:

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
            }

Я хочу добиться того же, но приведенный выше код не работает.
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

Я использую это:

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
Это хорошо, но применимо только к UILabel. Было бы намного лучше, если бы это было универсальное расширение, которое должно было бы принимать html и преобразовывать его в текст с атрибутами.
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
Кан Аксой

4

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

И наконец, вы можете создать 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
}

Результат:

введите описание изображения здесь

См. Учебник:

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


3

Для Swift 5 он также может загружать 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
        }
    }
}

После этого перейдите к своей строке, которую вы хотите преобразовать в NSAttributedString, и поместите ее, как в примере ниже:

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

введите описание изображения здесь Вот что принимает каждый параметр:

  • font: добавьте свой шрифт, как обычно, в UILabel / UITextView, используя UIFont с именем вашего пользовательского шрифта и размером.
  • csscolor: либо добавьте цвет в формате HEX, например «# 000000», либо используйте название цвета, например «черный».
  • lineheight: это пространство между строками, когда у вас есть несколько строк в UILabel / UITextView.
  • csstextalign: это выравнивание текста, значение, которое вам нужно добавить: «влево», «вправо», «по центру» или «по ширине».

Ссылка: https://johncodeos.com/how-to-display-html-in-uitextview-uilabel-with-custom-color-font-etc-in-ios-using-swift/


2

Попробуй это:

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

Надеюсь, это поможет.


Да, но это работает только для текста в HTML. Меня также беспокоили изображения и списки. Есть ли способ отображать изображения и списки одним объектом ??
Талха Ахмад Хан

3
Следует отметить, что использование NSHTMLTextDocumentTypeпроисходит очень медленно [1]. Попробуйте вместо этого использовать такую ​​библиотеку, как DDHTML . [1] robpeck.com/2015/04/nshtmltextdocumenttype-is-slow
Кристофер Кевин Хауэлл

2

Спасибо за приведенный выше ответ - 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 ?? ""
    }
}

1

Если вам нужен HTML с изображениями и списком, UILabel не поддерживает это. Однако я обнаружил, что YYText помогает.


Он поддерживается, если вы правильно кодируете строку. Где-то есть расширение attributedString для HTML
froggomad

1

Отображение изображений и абзацев текста невозможно UITextViewили UILabelдля этого необходимо использоватьUIWebView .

Просто добавьте элемент в раскадровку, ссылку на свой код и вызовите его для загрузки URL.

OBJ-C

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

Swift

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

Пошаговое руководство. http://sourcefreeze.com/uiwebview-example-using-swift-in-ios/


Это возможно в обоих случаях. Строку просто нужно правильно закодировать
froggomad

1

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

Вызов:

myLabel.attributedText = "myString".htmlAttributedString()

0

Я знаю, что это будет выглядеть немного чрезмерно, но ... Этот код добавит поддержку html в UILabel, UITextView, UIButton, и вы можете легко добавить эту поддержку в любое представление, которое имеет поддержку строк с атрибутами:

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

-1

ЕСЛИ У ВАС ИМЕЕТСЯ СТРОКА С HTML-КОДОМ ВНУТРИ, ВЫ МОЖЕТЕ ИСПОЛЬЗОВАТЬ:

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

И В ВАШЕМ КОДЕ ВЫ ИСПОЛЬЗУЕТЕ:

label.text = "something".htmlString
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.