Skip to content

Instantly share code, notes, and snippets.

@amichnia
Created November 6, 2019 13:38
Show Gist options
  • Save amichnia/63ac8c0107773651ccbde3b127b77c63 to your computer and use it in GitHub Desktop.
Save amichnia/63ac8c0107773651ccbde3b127b77c63 to your computer and use it in GitHub Desktop.
Swift: Convert basic raw html string to attributed string
import UIKit
extension String {
private var attributedStringOptions: [NSAttributedString.DocumentReadingOptionKey: Any] {
return [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
]
}
var wholeRange: NSRange {
return NSRange(location: 0, length: count)
}
var html2Attributed: NSAttributedString {
return attributedString()
}
func html2Attributed(
font: UIFont,
color: UIColor,
attributes: [NSAttributedString.Key: Any] = [:]
) -> NSAttributedString {
let base = attributedString(with: """
html * {
font-size: \(font.pointSize)pt !important;
font-family: \(font.familyName), Helvetica !important;
color: \(color.hexString) !important;
}
""")
base.beginEditing()
base.replaceFonts(with: font)
base.addAttributes(attributes, range: base.string.wholeRange)
base.endEditing()
return base
}
private func attributedString(with style: String = "") -> NSMutableAttributedString {
let base = NSMutableAttributedString(string: self)
guard let data = "<style>\(style)</style>\(self)".data(using: .utf8) else {
return base
}
return (try? NSMutableAttributedString(
data: data,
options: attributedStringOptions,
documentAttributes: nil
)) ?? base
}
}
extension UIColor {
var hexString: String {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
getRed(&r, green: &g, blue: &b, alpha: nil)
let rgb: Int = (Int)(r * 255) << 16 | (Int)(g * 255) << 8 | (Int)(b * 255) << 0
return NSString(format: "#%06x", rgb) as String
}
}
extension NSMutableAttributedString {
func replaceFonts(with font: UIFont) {
let descriptor = font.fontDescriptor
var changes: [NSRange: Any] = [:]
enumerateAttribute(.font, in: string.wholeRange, options: []) { foundFont, range, _ in
guard let traits = (foundFont as? UIFont)?.fontDescriptor.symbolicTraits else {
return
}
guard let adjustedDescriptor = descriptor.withSymbolicTraits(traits) else {
return
}
let newFont = UIFont(descriptor: adjustedDescriptor, size: font.pointSize)
changes[range] = newFont
}
changes.forEach { range, newValue in
removeAttribute(.font, range: range)
addAttribute(.font, value: newValue, range: range)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment