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.