Home > Net >  NSAttributedString: how to parse html tags and add attributes
NSAttributedString: how to parse html tags and add attributes

Time:08-11

I have some localization strings like this: "Register and get <b>all</b>\n<b>rewards cards</b> of our partners\n<b>in one</b> universal <b>card</b>"

So parts of it should be bold, and also there is a requirement for paragraph style.

This code works perfect for styling except bold parts:

let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 1.0
        paragraphStyle.alignment = .center
        paragraphStyle.minimumLineHeight = 18.0

let attributedString = NSMutableAttributedString(string: descriptionString, attributes: [.font: UIFont.proximaNovaRegularWithSize(size: 15.0),
                                                                                                 .paragraphStyle: paragraphStyle])

Also I have perfect solution to parse html tags:

func convertFromHTMLString(_ input: String?) -> NSMutableAttributedString? {
        guard let input = input else { return nil }

        guard let data = input.data(using: String.Encoding.unicode, allowLossyConversion: true) else { return nil  }
        return try? NSMutableAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html], documentAttributes: nil)
    }

But it's not working combined. So my question - how to parse html tags and add attributes to it? And the solution should be totally dynamic, to be used for different localization.

Note: I can't use markdown text as app should be available for iOS lower than 15.0

After used proposed solution

let attr = try? NSMutableAttributedString(
            data: data ?? Data(),
            options: [
                .documentType: NSAttributedString.DocumentType.html,
                .characterEncoding: String.Encoding.utf8.rawValue,
                .defaultAttributes: [
                    NSAttributedString.Key.font: UIFont.proximaNovaRegularWithSize(size: 15.0),
                    NSAttributedString.Key.paragraphStyle: paragraphStyle
                ],
            ],
            documentAttributes: nil
        )

result is: enter image description here

still no font and styling

CodePudding user response:

Try passing the attributes as defaultAttributes:

NSMutableAttributedString(
    data: data,
    options: [
        .documentType: NSAttributedString.DocumentType.html,
        .characterEncoding: String.Encoding.utf8.rawValue,
        .defaultAttributes: [
            NSAttributedString.Key.font: UIFont.proximaNovaRegularWithSize(size: 15.0),
            NSAttributedString.Key.paragraphStyle: paragraphStyle
        ],
    ],
    documentAttributes: nil
)

CodePudding user response:

Ok, I got the solution, maybe it will help anyone else.

Note, that my strings are strictly multi lined, so it's easy first split them, then add needed font and size to the parts, and then add paragraph styling.

I've played with order of parsing tags/styling fonts/styling paragraph, and at every case something was missed. If you don't need to separate line as multiline in strict order, just don't do mapping. Otherwise, you can miss breaking while styling or parsing tags. enter image description here

 descriptionLabel.attributedText = getAttributedDescriptionText(for: "Register and get <b>all</b>\n<b>rewards cards</b> of our partners\n<b>in one</b> universal <b>card</b>", fontDescription: "ProximaNova-Regular", fontSize: 15)   



func getAttributedDescriptionText(for descriptionString: String, fontDescription: String, fontSize: Int) -> NSAttributedString? {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = 1.0
    paragraphStyle.alignment = .center
    paragraphStyle.minimumLineHeight = 18.0

    let attributedString = NSMutableAttributedString()
    let splits = descriptionString.components(separatedBy: "\n")
    _ = splits.map { string in
        let modifiedFont = String(format:"<span style=\"font-family: '\(fontDescription)'; font-size: \(fontSize)\">%@</span>", string)
        let data = modifiedFont.data(using: String.Encoding.unicode, allowLossyConversion: true)
        let attr = try? NSMutableAttributedString(
            data: data ?? Data(),
            options: [
                .documentType: NSAttributedString.DocumentType.html,
                .characterEncoding: String.Encoding.utf8.rawValue
            ],
            documentAttributes: nil
        )
        attributedString.append(attr ?? NSMutableAttributedString())
        if string != splits.last {
            attributedString.append(NSAttributedString(string: "\n"))
        }
    }
    attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
    return attributedString
} 
  • Related