Je reçois de manière dynamique une chaîne HTML à partir d'une API Wordpress et je l'analyse en une chaîne attribuée pour l'afficher dans mon application. Comme la chaîne a ses propres styles, elle affiche différentes polices et tailles, quelque chose qui affecte nos choix de conception.
Ce que je veux faire, c'est changer la police et sa taille sur toute la chaîne attribuée.
J'ai essayé de le faire dans les options de la chaîne attribuée, mais cela ne fait rien:
let attributedT = try! NSAttributedString(
data: nContent!.decodeHTML().data(using: String.Encoding.unicode, allowLossyConversion: true)!,
options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSFontAttributeName: UIFont(name: "Helvetica", size: 16.0)!],
documentAttributes: nil)
contentLbl.attributedText = attributedT
Quelqu'un at-il des idées sur la façon d'y parvenir?
P.S. Je sais que je pourrais ajouter une balise CSS au début ou à la fin de la chaîne, mais cela remplacerait-il les autres styles? De plus, s'il s'agit d'une solution valide, pourriez-vous s'il vous plaît fournir un exemple sur la façon de le faire?
SetAttributes réinitialisera tous les attributs de HTML. J'ai écrit une méthode d'extension pour éviter cela:
Swift 4
public convenience init?(HTMLString html: String, font: UIFont? = nil) throws {
let options : [NSAttributedString.DocumentReadingOptionKey : Any] =
[NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue]
guard let data = html.data(using: .utf8, allowLossyConversion: true) else {
throw NSError(domain: "Parse Error", code: 0, userInfo: nil)
}
if let font = font {
guard let attr = try? NSMutableAttributedString(data: data, options: options, documentAttributes: nil) else {
throw NSError(domain: "Parse Error", code: 0, userInfo: nil)
}
var attrs = attr.attributes(at: 0, effectiveRange: nil)
attrs[NSAttributedStringKey.font] = font
attr.setAttributes(attrs, range: NSRange(location: 0, length: attr.length))
self.init(attributedString: attr)
} else {
try? self.init(data: data, options: options, documentAttributes: nil)
}
}
Échantillon de test:
let html = "<html><body><h1 style=\"color:red;\">html text here</h1></body></html>"
let font = UIFont.systemFont(ofSize: 16)
var attr = try NSMutableAttributedString(HTMLString: html, font: nil)
var attrs = attr?.attributes(at: 0, effectiveRange: nil)
attrs?[NSAttributedStringKey.font] as? UIFont
// print: <UICTFont: 0x7ff19fd0a530> font-family: "TimesNewRomanPS-BoldMT"; font-weight: bold; font-style: normal; font-size: 24.00pt
attr = try NSMutableAttributedString(HTMLString: html, font: font)
attrs = attr?.attributes(at: 0, effectiveRange: nil)
attrs?[NSAttributedStringKey.font] as? UIFont
// print: <UICTFont: 0x7f8c0cc04620> font-family: ".SFUIText"; font-weight: normal; font-style: normal; font-size: 16.00pt
Ce que vous voulez faire, fondamentalement, c'est transformer la NSAttributedString en NSMutableAttributedString.
let attributedT = // ... attributed string
let mutableT = NSMutableAttributedString(attributedString:attributedT)
Vous pouvez maintenant appeler addAttributes
pour appliquer des attributs, tels qu'une police différente, sur n'importe quelle plage souhaitée, comme le tout.
Malheureusement, cependant, une police sans trait symbolique tel que l'italique est une police différente d'une police avec ce trait symbolique. Par conséquent, vous allez avoir besoin d'un utilitaire qui copie les traits symboliques existants d'une police et les applique à une autre police:
func applyTraitsFromFont(_ f1: UIFont, to f2: UIFont) -> UIFont? {
let t = f1.fontDescriptor.symbolicTraits
if let fd = f2.fontDescriptor.withSymbolicTraits(t) {
return UIFont.init(descriptor: fd, size: 0)
}
return nil
}
D'accord, donc, armé de cet utilitaire, essayons-le. Je vais commencer avec du HTML simple et le convertir en une chaîne attribuée, comme vous le faites:
let html = "<p>Hello <i>world</i>, hello</p>"
let data = html.data(using: .utf8)!
let att = try! NSAttributedString.init(
data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
let matt = NSMutableAttributedString(attributedString:att)
Comme vous pouvez le voir, je l'ai converti en NSMutableAttributedString, comme je l'ai conseillé. Maintenant, je vais parcourir les styles en termes de police, en modifiant une police différente tout en utilisant mon utilitaire pour appliquer les traits existants:
matt.enumerateAttribute(
NSFontAttributeName,
in:NSMakeRange(0,matt.length),
options:.longestEffectiveRangeNotRequired) { value, range, stop in
let f1 = value as! UIFont
let f2 = UIFont(name:"Georgia", size:20)!
if let f3 = applyTraitsFromFont(f1, to:f2) {
matt.addAttribute(
NSFontAttributeName, value:f3, range:range)
}
}
Voici le résultat:
Évidemment, vous pouvez modifier cette procédure pour être encore plus sophistiqué, en fonction de vos besoins de conception.
Swift 4 solution
NSAttributedString
extension avec initialiseur pratiqueUIFont
fournisUIFont
, @see useDocumentFontSize
fourniguard
extension NSAttributedString {
convenience init(htmlString html: String, font: UIFont? = nil, useDocumentFontSize: Bool = true) throws {
let options: [NSAttributedString.DocumentReadingOptionKey : Any] = [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
]
let data = html.data(using: .utf8, allowLossyConversion: true)
guard (data != nil), let fontFamily = font?.familyName, let attr = try? NSMutableAttributedString(data: data!, options: options, documentAttributes: nil) else {
try self.init(data: data ?? Data(html.utf8), options: options, documentAttributes: nil)
return
}
let fontSize: CGFloat? = useDocumentFontSize ? nil : font!.pointSize
let range = NSRange(location: 0, length: attr.length)
attr.enumerateAttribute(.font, in: range, options: .longestEffectiveRangeNotRequired) { attrib, range, _ in
if let htmlFont = attrib as? UIFont {
let traits = htmlFont.fontDescriptor.symbolicTraits
var descrip = htmlFont.fontDescriptor.withFamily(fontFamily)
if (traits.rawValue & UIFontDescriptorSymbolicTraits.traitBold.rawValue) != 0 {
descrip = descrip.withSymbolicTraits(.traitBold)!
}
if (traits.rawValue & UIFontDescriptorSymbolicTraits.traitItalic.rawValue) != 0 {
descrip = descrip.withSymbolicTraits(.traitItalic)!
}
attr.addAttribute(.font, value: UIFont(descriptor: descrip, size: fontSize ?? htmlFont.pointSize), range: range)
}
}
self.init(attributedString: attr)
}
}
sage-1 (Remplacer la police)
let attr = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!", font: UIFont.systemFont(ofSize: 34, weight: .thin))
sage-2 (NSMutableAttributedString
exemple)
let attr = try! NSMutableAttributedString(htmlString: "<strong>Hello</strong> World!", font: UIFont.systemFont(ofSize: 34, weight: .thin))
attr.append(NSAttributedString(string: " MINIMIZE", attributes: [.link: "@m"]))
sage-3 (convertir uniquement HTML en NSAttributedString)
let attr = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!")
Swift version de ma précédente solution (Swift 4)
extension NSAttributedString {
convenience init(htmlString html: String, font: UIFont? = nil, useDocumentFontSize: Bool = true) throws {
let options: [String : Any] = [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue
]
let data = html.data(using: .utf8, allowLossyConversion: true)
guard (data != nil), let fontFamily = font?.familyName, let attr = try? NSMutableAttributedString(data: data!, options: options, documentAttributes: nil) else {
try self.init(data: data ?? Data(html.utf8), options: options, documentAttributes: nil)
return
}
let fontSize: CGFloat? = useDocumentFontSize ? nil : font!.pointSize
let range = NSRange(location: 0, length: attr.length)
attr.enumerateAttribute(NSFontAttributeName, in: range, options: .longestEffectiveRangeNotRequired) { attrib, range, _ in
if let htmlFont = attrib as? UIFont {
let traits = htmlFont.fontDescriptor.symbolicTraits
var descrip = htmlFont.fontDescriptor.withFamily(fontFamily)
if (traits.rawValue & UIFontDescriptorSymbolicTraits.traitBold.rawValue) != 0 {
descrip = descrip.withSymbolicTraits(.traitBold)!
}
if (traits.rawValue & UIFontDescriptorSymbolicTraits.traitItalic.rawValue) != 0 {
descrip = descrip.withSymbolicTraits(.traitItalic)!
}
attr.addAttribute(NSFontAttributeName, value: UIFont(descriptor: descrip, size: fontSize ?? htmlFont.pointSize), range: range)
}
}
self.init(attributedString: attr)
}
}
let font = "<font face='Montserrat-Regular' size='13' color= 'black'>%@"
let html = String(format: font, yourhtmlstring)
webView.loadHTMLString(html, baseURL: nil)