J'ai essayé d'appliquer des combinaisons de NSFontAttributes à NSMutableAttributedString récemment et je ne trouve tout simplement pas d'explication détaillée sur la façon de le faire sans supprimer d'autres attributs.
J'ai cherché un tas, et j'ai trouvé ceci question concernant la façon de le faire avec HTML, puis ce question sur la façon de trouver = où le texte a été mis en gras ou en italique, mais rien sur la façon de le faire.
Actuellement, j'essaie de formater les piqûres comme suit:
Italique: [mutableAttributedString addAttribute: NSFontAttributeName value:[fontAttributes valueForKey:CXItalicsFontAttributeName] range:r];
Gras: [mutableAttributedString addAttribute:NSFontAttributeName value:[fontAttributes valueForKey:CXBoldFontAttributeName] range:r];
Où les constantes CXItalicsFontAttributeName
et CXBoldAttributeName
extraient les deux valeurs suivantes d'un dictionnaire avec respect:
UIFont *italicsFont = [UIFont fontWithName:@"Avenir-BookOblique" size:14.0f];
UIFont *boldFont = [UIFont fontWithName:@"Avenir-Heavy" size:14.0f];
Je sais que cela ne doit pas être la bonne façon de procéder au formatage, car NSAttributedString attributs standard n'inclut pas ItalicsFontAttribute ou BoldFontAttribute, mais je ne trouve pas la bonne façon de le faire. Quelqu'un peut-il m'aider?
Si vous appliquez chaque trait (gras ou italique) individuellement, vous devez vous assurer que les plages en gras et en italique ne se chevauchent pas ou un trait écrasera l'autre.
La seule façon d'appliquer les caractères italiques gras et à une plage est d'utiliser une police qui est à la fois en gras et en italique, et d'appliquer les deux traits à la fois .
let str = "Normal Bold Italics BoldItalics"
let font = UIFont(name: "Avenir", size: 14.0)!
let italicsFont = UIFont(name: "Avenir-BookOblique", size: 14.0)!
let boldFont = UIFont(name: "Avenir-Heavy", size: 14.0)!
let boldItalicsFont = UIFont(name: "Avenir-HeavyOblique", size: 14.0)!
let attributedString = NSMutableAttributedString(string: str, attributes: [NSFontAttributeName : font])
attributedString.addAttribute(NSFontAttributeName, value: boldFont, range: NSMakeRange(7, 4))
attributedString.addAttribute(NSFontAttributeName, value: italicsFont, range: NSMakeRange(12, 7))
attributedString.addAttribute(NSFontAttributeName, value: boldItalicsFont, range: NSMakeRange(20, 11))
Dans Swift et en utilisant une extension:
extension UIFont {
func withTraits(_ traits: UIFontDescriptorSymbolicTraits) -> UIFont {
// create a new font descriptor with the given traits
guard let fd = fontDescriptor.withSymbolicTraits(traits) else {
// the given traits couldn't be applied, return self
return self
}
// return a new font with the created font descriptor
return UIFont(descriptor: fd, size: pointSize)
}
func italics() -> UIFont {
return withTraits(.traitItalic)
}
func bold() -> UIFont {
return withTraits(.traitBold)
}
func boldItalics() -> UIFont {
return withTraits([ .traitBold, .traitItalic ])
}
}
Exemple:
if let font = UIFont(name: "Avenir", size: 30) {
let s = NSAttributedString(string: "Hello World!", attributes: [ NSFontAttributeName: font.italic() ])
let t = NSAttributedString(string: "Hello World!", attributes: [ NSFontAttributeName: font.boldItalic()) ])
}
Jusqu'à présent, la meilleure solution à mon problème a été d'utiliser la classe UIFontDescriptor
pour me fournir le UIFont
nécessaire pour chaque cas rencontré.
Par exemple, comme je veux utiliser Avenir-Book
comme ma police principale avec une taille 14
, Je peux créer un UIFontDescriptor
comme suit:
UIFontDescriptor *fontDescriptor = [UIFontDescriptor fontDescriptorWithName:@"Avenir-Book" size:14.0f];
Ensuite, si je souhaite obtenir les caractères italiques, en gras ou une combinaison des deux, j'ai simplement à faire comme suit:
NSString *normalFont = [[fontDescriptor fontAttributes]valueForKey:UIFontDescriptorNameAttribute];
NSString *italicsFont = [[[fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic]fontAttributes]valueForKey:UIFontDescriptorNameAttribute];
NSString *boldFont = [[[fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold]fontAttributes]valueForKey:UIFontDescriptorNameAttribute];
NSString *boldAndItalicsFont = [[[fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic]fontAttributes]valueForKey:UIFontDescriptorNameAttribute];
Et cela produit en effet les polices requises lors de l'impression:
NSLog(@"Normal Font: %@ Size: %@\n",normalFont,[[fontDescriptor fontAttributes]valueForKey:UIFontDescriptorSizeAttribute]);
NSLog(@"Italics Font: %@\n",italicsFont);
NSLog(@"Bold Font: %@\n",boldFont);
NSLog(@"Bold and Italics Font: %@\n",boldAndItalicsFont);
Sortie:
Normal Font: Avenir-Book Size: 14
Italics Font: Avenir-BookOblique
Bold Font: Avenir-Black
Bold and Italics Font: Avenir-BlackOblique
L'avantage ici est que je n'ai plus besoin de créer moi-même les types de polices individuels, et une police de la famille est suffisante pour le faire.
Check-out NSAttributedString.Key.obliqueness
. Si la valeur de cette clé est différente de 0, le texte en italique est de degré différent.
extension UIFont {
class func systemFont(ofSize fontSize: CGFloat, symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont? {
return UIFont.systemFont(ofSize: fontSize).including(symbolicTraits: symbolicTraits)
}
func including(symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont? {
var _symbolicTraits = self.fontDescriptor.symbolicTraits
_symbolicTraits.update(with: symbolicTraits)
return withOnly(symbolicTraits: _symbolicTraits)
}
func excluding(symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont? {
var _symbolicTraits = self.fontDescriptor.symbolicTraits
_symbolicTraits.remove(symbolicTraits)
return withOnly(symbolicTraits: _symbolicTraits)
}
func withOnly(symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont? {
guard let fontDescriptor = fontDescriptor.withSymbolicTraits(symbolicTraits) else { return nil }
return .init(descriptor: fontDescriptor, size: pointSize)
}
}
font = UIFont.italicSystemFont(ofSize: 15).including(symbolicTraits: .traitBold)
font = UIFont.systemFont(ofSize: 15, symbolicTraits: [.traitBold, .traitItalic])
font = font.excluding(symbolicTraits: [.traitBold]
font = font.withOnly(symbolicTraits: [])
N'oubliez pas de coller le code de la solution ici .
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addLabel(Origin: .init(x: 20, y: 20), font: .systemFont(ofSize: 15, symbolicTraits: [.traitBold, .traitItalic]))
addLabel(Origin: .init(x: 20, y: 40), font: UIFont.italicSystemFont(ofSize: 15).including(symbolicTraits: .traitBold))
guard let font = UIFont.systemFont(ofSize: 15, symbolicTraits: [.traitBold, .traitItalic]) else { return }
addLabel(Origin: .init(x: 20, y: 60), font: font.excluding(symbolicTraits: [.traitBold]))
addLabel(Origin: .init(x: 20, y: 80), font: font.withOnly(symbolicTraits: []))
}
private func addLabel(Origin: CGPoint, font: UIFont?) {
guard let font = font else { return }
let label = UILabel(frame: .init(Origin: Origin, size: .init(width: 200, height: 40)))
label.attributedText = NSAttributedString(string: "Hello World!", attributes: [.font: font, .foregroundColor: UIColor.black ])
view.addSubview(label)
}
}