问题
I have a number of UILabels created in IB which all have attributed text. Each label's text contains multiple lines of different font sizes and colors.
At run-time, I want to be able to change just the font name of these labels without changing the existing font sizes or colors.
I have researched and could not find a straight forward method to achieve this. Any ideas?
回答1:
You first need to understand the lingo Apple uses to describe a typeface:
Helvetica
is a familyHelvetica Bold
,Helvetica Italic
,Helvetica Bold Italic
,Helvetica Display
etc. are facesHelvetica Bold, 12pt
is a font
What you want is to replace the font family of an attributed string.
Swift 4
// Enumerate through all the font ranges
newAttributedString.enumerateAttribute(.font, in: NSMakeRange(0, newAttributedString.length), options: []) { value, range, stop in
guard let currentFont = value as? UIFont else {
return
}
// An NSFontDescriptor describes the attributes of a font: family name,
// face name, point size, etc. Here we describe the replacement font as
// coming from the "Hoefler Text" family
let fontDescriptor = currentFont.fontDescriptor.addingAttributes([.family: "Hoefler Text"])
// Ask the OS for an actual font that most closely matches the description above
if let newFontDescriptor = fontDescriptor.matchingFontDescriptors(withMandatoryKeys: [.family]).first {
let newFont = UIFont(descriptor: newFontDescriptor, size: currentFont.pointSize)
newAttributedString.addAttributes([.font: newFont], range: range)
}
}
label.attributedText = newAttributedString
Swift 3
let newAttributedString = NSMutableAttributedString(attributedString: label.attributedText)
// Enumerate through all the font ranges
newAttributedString.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, newAttributedString.length), options: []) { value, range, stop in
guard let currentFont = value as? UIFont else {
return
}
// An NSFontDescriptor describes the attributes of a font: family name,
// face name, point size, etc. Here we describe the replacement font as
// coming from the "Hoefler Text" family
let fontDescriptor = currentFont.fontDescriptor.addingAttributes([UIFontDescriptorFamilyAttribute: "Hoefler Text"])
// Ask the OS for an actual font that most closely matches the description above
if let newFontDescriptor = fontDescriptor.matchingFontDescriptors(withMandatoryKeys: [UIFontDescriptorFamilyAttribute]).first {
let newFont = UIFont(descriptor: newFontDescriptor, size: currentFont.pointSize)
newAttributedString.addAttributes([NSFontAttributeName: newFont], range: range)
}
}
label.attributedText = newAttributedString
Original (San Francisco):
Replacement (Hoefler Text):
回答2:
The above works great but with Swift4 and Xcode 9.1 I got number of warnings that method names had changed. Below is the result of applying all those warnings. Otherwise I did not change anything.
let newAttributedString = NSMutableAttributedString(attributedString: label.attributedText!)
// Enumerate through all the font ranges
newAttributedString.enumerateAttribute(NSAttributedStringKey.font, in: NSMakeRange(0, newAttributedString.length), options: [])
{
value, range, stop in
guard let currentFont = value as? UIFont else {
return
}
// An NSFontDescriptor describes the attributes of a font: family name, face name, point size, etc.
// Here we describe the replacement font as coming from the "Hoefler Text" family
let fontDescriptor = currentFont.fontDescriptor.addingAttributes([UIFontDescriptor.AttributeName.family: "Hoefler Text"])
// Ask the OS for an actual font that most closely matches the description above
if let newFontDescriptor = fontDescriptor.matchingFontDescriptors(withMandatoryKeys: [UIFontDescriptor.AttributeName.family]).first {
let newFont = UIFont(descriptor: newFontDescriptor, size: currentFont.pointSize)
newAttributedString.addAttributes([NSAttributedStringKey.font: newFont], range: range)
}
}
label.attributedText = newAttributedString
来源:https://stackoverflow.com/questions/42318020/change-just-font-of-attributedtext-in-swift