47

I would like to display html formatted text on a UILabel in IOS.

In Android, it has api like this .setText(Html.fromHtml(somestring));

Set TextView text from html-formatted string resource in XML

I would like to know what / if there is an equivalent in ios?

I search and find this thread:

How to show HTML text from API on the iPhone?

But it suggests using UIWebView. I need to display html formatted string in each table cell, so I think have 1 webview per row seems a bit heavy.

Is that any other alternative?

Thank you.

Shruti Thombre
  • 989
  • 4
  • 11
  • 27
hap497
  • 154,439
  • 43
  • 83
  • 99

7 Answers7

57

Swift 3.0

do {
    let attrStr = try NSAttributedString(
        data: "<b><i>text</i></b>".data(using: String.Encoding.unicode, allowLossyConversion: true)!,
        options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil)
    label.attributedText = attrStr
} catch let error {

}
chengsam
  • 7,315
  • 6
  • 30
  • 38
ƒernando Valle
  • 3,634
  • 6
  • 36
  • 58
  • 3
    Worked for me. Can freely use 'let' instead of 'var' on the example. – alasker Feb 04 '17 at 19:51
  • 1
    You shouldn't use `try!` because an exception may be thrown. – chengsam Jun 05 '17 at 05:05
  • @fernandi Valle . If i want text with html tags means how can i achieve this – Uma Madhavi Jun 06 '17 at 11:09
  • @UmaMadhavi what kind of html tags? because not every are compatibles. – ƒernando Valle Jun 06 '17 at 13:07
  • hello similar to this – Uma Madhavi Jun 06 '17 at 13:08
  • You have the answer at top.¯\_(ツ)_/¯ data: "text".data(..... – ƒernando Valle Jun 06 '17 at 13:15
  • How I can set the font color also? – Andreas777 Jun 21 '17 at 15:11
  • @Andreas777 that's a html question but I will reply you, you can add style as

    This is a paragraph.

    for example. take a look here: https://www.w3schools.com/html/html_styles.asp
    – ƒernando Valle Jun 22 '17 at 07:31
  • Well is kinda not an HTML question, because in my case and many apps return HTML from an API and you need some more generic way, than parsing the HTML and setting color for different cases with CSS. The way it worked for me was to convert the NSAttributedString to NSMutableAttributedString and addAttribute(font, color etc). The thing is that still can't diplay correct format when if I have tags for example. Does the formatting works for you or just displays the HTML? – Andreas777 Jun 22 '17 at 07:39
  • @Andreas777 I am facing the same problem of Bold tag. You got it working? Please suggestion if you found some hack – Vinayak Parmar Aug 05 '17 at 16:37
50

for Swift 2.0:

var attrStr = try! NSAttributedString(
        data: "<b><i>text</i></b>".dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!,
        options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil)
label.attributedText = attrStr
Daniele B
  • 19,801
  • 29
  • 115
  • 173
29

Swift 4

import UIKit
let htmlString = "<html><body> Some <b>html</b> string </body></html>"
// works even without <html><body> </body></html> tags, BTW 
let data = htmlString.data(using: String.Encoding.unicode)! // mind "!"
let attrStr = try? NSAttributedString( // do catch
    data: data,
    options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
    documentAttributes: nil)
// suppose we have an UILabel, but any element with NSAttributedString will do
label.attributedText = attrStr

Supplement: controlling the font of resulting formatted string

To use properly scaled (i.e. with respect to user settings) system (or any other) font you may do the following.

let newFont = UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: UIFont.systemFontSize)) // The same is possible for custom font.

let mattrStr = NSMutableAttributedString(attributedString: attrStr!)
mattrStr.beginEditing()
mattrStr.enumerateAttribute(.font, in: NSRange(location: 0, length: mattrStr.length), options: .longestEffectiveRangeNotRequired) { (value, range, _) in
    if let oFont = value as? UIFont, let newFontDescriptor = oFont.fontDescriptor.withFamily(newFont.familyName).withSymbolicTraits(oFont.fontDescriptor.symbolicTraits) {
        let nFont = UIFont(descriptor: newFontDescriptor, size: newFont.pointSize)
        mattrStr.removeAttribute(.font, range: range)
        mattrStr.addAttribute(.font, value: nFont, range: range)
    }
}
mattrStr.endEditing()
label.attributedText = mattrStr
Paul B
  • 3,989
  • 33
  • 46
  • This worked perfectly for me! However, is there a way to have it pick-up the font that's being used by the rest of the app without having to define the font family and size for every

    or

    tag? In my case I'm just using the system font.

    – jammyman34 Feb 25 '19 at 19:16
  • Good question, @ammyman34. Tried my best to provide exhaustive answer. – Paul B Feb 26 '19 at 10:34
  • Thanks Paul, I really appreciate your willingness to help! Unfortunately, I can't get it to work. Also, when I added this second set of code Xcode told me it would only work in iOS11.0 or later and wrapped it in an If #available(iOS 11.0, *){ } condition... when I build it, it's still rendering my html content, but it's not picking up the font family styling of the app, which is SanFrancisco (i.e. the default), but is showing it as a serifed font, like Times. Also, not sure if this matters, but I had to put all of this in the viewDidLoad function or else it wouldn't build. – jammyman34 Feb 28 '19 at 22:55
  • Maybe sometimes it is necessary to removeAttribute(.font, range: range) before addAttribute(.font, range: range). iOS11 compatibility is likely UIFontMetrics requirement. You may calculate size manually for prior versions. – Paul B Mar 01 '19 at 07:55
23

You could try an attributed string:

var attrStr = NSAttributedString(
        data: "<b><i>text</i></b>".dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true),
        options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil,
        error: nil)
label.attributedText = attrStr
Connor Pearson
  • 63,902
  • 28
  • 145
  • 142
1

Objective-C Version:

   NSError *error = nil;
   NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:contentData
                                                    options:@{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType}
                                                    documentAttributes:nil error:&error];

This is just the Objective-C conversion of the above answers. All the answers above are right and reference taken from the above answers for this.

Er. Vihar
  • 1,495
  • 1
  • 15
  • 29
0

For me, Paul's answer worked. But for custom fonts I had to put following hack.

//Please take care of force unwrapping
let data = htmlString.data(using: String.Encoding.unicode)! 
        let mattrStr = try! NSMutableAttributedString(
            data: data,
            options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
            documentAttributes: nil)
        let normalFont = UIFontMetrics.default.scaledFont(for: UIFont(name: "NormalFontName", size: 15.0)!)//
        let boldFont = UIFontMetrics.default.scaledFont(for: UIFont(name: "BoldFontName", size: 15.0)!)
        mattrStr.beginEditing()
        mattrStr.enumerateAttribute(.font, in: NSRange(location: 0, length: mattrStr.length), options: .longestEffectiveRangeNotRequired) { (value, range, _) in
            if let oFont = value as? UIFont{
                mattrStr.removeAttribute(.font, range: range)
                if oFont.fontName.contains("Bold"){
                    mattrStr.addAttribute(.font, value: boldFont, range: range)
                }
                else{
                    mattrStr.addAttribute(.font, value: normalFont, range: range)
                }

            }
        }
Pranav Pravakar
  • 205
  • 3
  • 7
-1
Try this:

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 ""
    }
Hope its helpful.
Ved Rauniyar
  • 1,539
  • 14
  • 21