How to display html formatted text in ios label
Asked Answered
R

7

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.

Remanent answered 16/9, 2014 at 23:15 Comment(1)
OHAttributedLabel may help you github.com/AliSoftware/OHAttributedLabelSomnifacient
S
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 {

}
Solus answered 16/11, 2016 at 9:15 Comment(10)
Worked for me. Can freely use 'let' instead of 'var' on the example.Colp
You shouldn't use try! because an exception may be thrown.Gemology
@fernandi Valle . If i want text with html tags means how can i achieve thisChutzpah
@UmaMadhavi what kind of html tags? because not every are compatibles.Fennelly
<b>hello</b> similar to thisChutzpah
You have the answer at top.¯_(ツ)_/¯ data: "<b><i>text</i></b>".data(.....Fennelly
How I can set the font color also?Sectarianize
@Sectarianize that's a html question but I will reply you, you can add style as <p style="color:red;">This is a paragraph.</p> for example. take a look here: w3schools.com/html/html_styles.aspFennelly
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 <bold> tags for example. Does the formatting works for you or just displays the HTML?Sectarianize
@Sectarianize I am facing the same problem of Bold tag. You got it working? Please suggestion if you found some hackPetta
A
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
Ashantiashbaugh answered 28/10, 2015 at 14:46 Comment(3)
How to change text color of this string? Is it possible to change color. I tried adding NSForegroundColorAttributeName but this didn't helped.Etan
Does it support also images?Fite
So has anyone figured out how to change the font color and font? I tried both, but it seems no other options work with that document type attribute setTheocracy
K
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
Kanya answered 12/3, 2018 at 16:3 Comment(4)
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 <H2> or <P> tag? In my case I'm just using the system font.Woorali
Good question, @ammyman34. Tried my best to provide exhaustive answer.Kanya
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.Woorali
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.Kanya
O
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
Oys answered 16/9, 2014 at 23:28 Comment(6)
fyi this method is very slow on iOS8Reliance
Thank you! This is fantastic! And not slow at all in iOS 8 in this dev's experience.Wallace
I get the error: Cannot invoke initializer for type 'NSAttributedString' with an argument list of type '(data: NSData?, options: [String : String], documentAttributes: _, error: _)'Ashantiashbaugh
It doesn't work for Swift 2.0. See solution in the new answer.Ashantiashbaugh
getting error "Type of expression is ambigious without more context"Xylem
my string is like "Hello <a href='#/userProfile/NA==\n/MQ==\n' target='_blank'>@mansuu</a>". @connorGallimaufry
K
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.

Koala answered 1/4, 2020 at 10:7 Comment(0)
W
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)
                }

            }
        }
Worldbeater answered 21/4, 2019 at 9:44 Comment(0)
H
-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.
Hepburn answered 1/2, 2017 at 6:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.