Swift: Відображення даних HTML у мітці або textView


86

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

Чи є спосіб відобразити ці дані в одному UITextViewабо UILabel?


1
Використовуйте UIWebView замість UITextView або UILabel. Тож він буде відображатись із зображеннями
— Тайсон Віньєш,

Так, я думаю, ти маєш рацію @TysonVignesh
— Ahmad Khan

@TysonVignesh Як я можу використовувати UIWebView для відображення html?
— Mohamed Ezzat

2
@MohamedEzzat див. Це посилання hackingwithswift.com/example-code/uikit/…
— Талха Ахмад Хан

Відповіді:


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
@Roger Carvalho: Чи є спосіб встановити сімейство шрифтів, -розмір тощо для вміщених тегів html?
— Bernhard Engl

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
Як я можу додати власний шрифт?
— Bhavin Ramani

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
            }

Я хочу досягти того ж, але наведений вище код не працює.
— Пратюш Пратік

7

Свіфт 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.AsifNoror

4

Стрімкий 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

4

Стрімкий 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")

введіть тут опис зображення Ось що бере кожен параметр:

  • шрифт: Додайте шрифт, як це зазвичай роблять у UILabel / UITextView, використовуючи UIFont із назвою власного шрифту та розміром.
  • csscolor: Або додайте колір у шістнадцятковому форматі, наприклад "# 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

Thx для наведеної вище відповіді тут є 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

Відображення зображень та текстових абзаців неможливо в a, UITextViewабо UILabelдля цього потрібно використовувати a UIWebView.

Просто додайте елемент у розкадрування, прив’яжіть до свого коду та зателефонуйте йому, щоб завантажити URL-адресу.

OBJ-C

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

Стрімкий

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

Стрімкий 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.