Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse HTML into NSAttributedString with San Francisco Font? (iOS 9)

I need to parse basic HTML Strings containing <b>(bold), <i>(italic), and <u>(underline) tags, nothing else, just those simple tags.

Right now I can only get the <u>(underline) tags to render properly in the NSAttributedString, when using the new San Francisco in iOS 9.

I really need to get <b>(bold) and <i>(italic) to render as well.

Here's what I'm doing:

let text = "<i>Any</i> <b>Text</b> <u>that's basic HTML</u>"
let font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)

let modifiedFont = NSString(format:"<span style=\"font-family: '-apple-system','HelveticaNeue'; font-size: %f \">%@</span>",
font.pointSize, text) as String

let data = (modifiedFont as NSString).dataUsingEncoding(NSUTF8StringEncoding)

let attributedString = try? NSAttributedString(data: data!, options:
            [ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
                NSCharacterEncodingDocumentAttribute : NSUTF8StringEncoding,
                NSFontAttributeName : font ],
            documentAttributes: nil)

But unfortunately the <i>(italic) and <b>(bold) tags never render, only <u>(underline) renders correctly.

This same exact method used to work on iOS 8 with Helvetica-Neue font, but it's not working with the new iOS 9 San Francisco font

Help me get <b>(bold) and <i>(italic) to render properly in an NSAttributedString!

Update: I am using Dynamic Text throughout the application as well. This may be a cause of why things aren't working...

like image 385
Sakiboy Avatar asked Oct 28 '15 04:10

Sakiboy


1 Answers

Using both NSAttributedString and DynamicType in the app is what caused the problem.

As it turns out you NEED to re-parse/render your String after receiving the UIContentSizeCategoryDidChangeNotification. You CANNOT retain the NSAttributedString and then use it to reset the text in your UILabel. You must re-parse/render the NSAttributedString.

Brief Example:

public override func viewDidLoad() {
    super.viewDidLoad()

    //register be notified when text size changes.
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("didChangePreferredContentSize:"), name: UIContentSizeCategoryDidChangeNotification, object: nil)
}

// The action Selector that gets called after the text size has been changed.
func didChangePreferredContentSize(notification: NSNotification) {
    self.myLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
    //
    // DO NOT do this:
    // self.myLabel.attributedText = self.myAlreadyRenderedText
    //
    //Make sure you re-render/parse the text into a new NSAttributedString.
    //Do THIS instead:
    self.myLabel.attributedText = self.renderAttributedText(str)
}

//Our method to render/parse the HTML tags in our text. Returns an NSAttributedString.
func renderAttributedText(str: String) -> NSAttributedString? {
    let text = "<i>Any</i> <b>Text</b> <u>that's basic HTML</u>"
    let font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)

    let modifiedFont = NSString(format:"<span style=\"font-family: '-apple-system','HelveticaNeue'; font-size: %f \">%@</span>",font.pointSize, text) as String

    let data = (modifiedFont as NSString).dataUsingEncoding(NSUTF8StringEncoding)

    let attributedString = try? NSAttributedString(data: data!, options:
        [ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
            NSCharacterEncodingDocumentAttribute : NSUTF8StringEncoding,
            NSFontAttributeName : font ],
        documentAttributes: nil)

    return attributedString
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}
like image 60
Sakiboy Avatar answered Oct 20 '22 01:10

Sakiboy