Nsattributedstring, Change the Font Overall But Keep All Other Attributes

NSAttributedString, change the font overall BUT keep all other attributes?

Since rmaddy's answer did not work for me (f.fontDescriptor.withFace(font.fontName) does not keep traits like bold), here is an updated Swift 4 version that also includes color updating:

extension NSMutableAttributedString {
func setFontFace(font: UIFont, color: UIColor? = nil) {
beginEditing()
self.enumerateAttribute(
.font,
in: NSRange(location: 0, length: self.length)
) { (value, range, stop) in

if let f = value as? UIFont,
let newFontDescriptor = f.fontDescriptor
.withFamily(font.familyName)
.withSymbolicTraits(f.fontDescriptor.symbolicTraits) {

let newFont = UIFont(
descriptor: newFontDescriptor,
size: font.pointSize
)
removeAttribute(.font, range: range)
addAttribute(.font, value: newFont, range: range)
if let color = color {
removeAttribute(
.foregroundColor,
range: range
)
addAttribute(
.foregroundColor,
value: color,
range: range
)
}
}
}
endEditing()
}
}

Or, if your mix-of-attributes does not include font,

then you don't need to remove old font:

let myFont: UIFont = .systemFont(ofSize: UIFont.systemFontSize);

myAttributedText.addAttributes(
[NSAttributedString.Key.font: myFont],
range: NSRange(location: 0, length: myAttributedText.string.count));


Notes

The problem with f.fontDescriptor.withFace(font.fontName) is that it removes symbolic traits like italic, bold or compressed, since it will for some reason override those with default traits of that font face. Why this is so totally eludes me, it might even be an oversight on Apple's part; or it's "not a bug, but a feature", because we get the new font's traits for free.

So what we have to do is create a font descriptor that has the symbolic traits from the original font's font descriptor: .withSymbolicTraits(f.fontDescriptor.symbolicTraits). Props to rmaddy for the initial code on which I iterated.

I've already shipped this in a production app where we parse a HTML string via NSAttributedString.DocumentType.html and then change the font and color via the extension above. No problems so far.

Change only fontsize of NSAttributedString

If you only want to change the size of any given font found in the attributed string then you can do:

let newStr = someAttributedString.mutableCopy() as! NSMutableAttributedString
newStr.beginEditing()
newStr.enumerateAttribute(.font, in: NSRange(location: 0, length: newStr.string.utf16.count)) { (value, range, stop) in
if let oldFont = value as? UIFont {
let newFont = oldFont.withSize(20) // whatever size you need
newStr.addAttribute(.font, value: newFont, range: range)
}
}
newStr.endEditing()

print(newStr)

This will keep all other attributes in place.

If you want to replace all fonts in a given attributed string with a single font of a given size but keep all other attributes such as bold and italic, see:
NSAttributedString, change the font overall BUT keep all other attributes?

Looping Through NSAttributedString Attributes to Increase Font SIze

Something like this should work:

NSMutableAttributedString *res = [self.richTextEditor.attributedText mutableCopy];

[res beginEditing];
__block BOOL found = NO;
[res enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, res.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
UIFont *oldFont = (UIFont *)value;
UIFont *newFont = [oldFont fontWithSize:oldFont.pointSize * 2];
[res removeAttribute:NSFontAttributeName range:range];
[res addAttribute:NSFontAttributeName value:newFont range:range];
found = YES;
}
}];
if (!found) {
// No font was found - do something else?
}
[res endEditing];
self.richTextEditor.attributedText = res;

At this point res has a new attributed string with all fonts being twice their original size.

How to set font size on NSAttributedString

let myString = "Swift Attributed String"
let myAttribute = [ NSForegroundColorAttributeName: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)

// set attributed text on a UILabel
myLabel.attributedText = myAttrString

Font

let myAttribute = [ NSFontAttributeName: UIFont(name: "Chalkduster", size: 18.0)! ]

Shadow

let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray
let myAttribute = [ NSShadowAttributeName: myShadow ]

Underline

let myAttribute = [ NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue ]

Textcolor

let myAttribute = [ NSForegroundColorAttributeName: UIColor.blue ]

Background Color

let myAttribute = [ NSBackgroundColorAttributeName: UIColor.yellow ]

NSAttributedString background color is not solid when other attributes are applied

There is an attribute called expansion that adjusts the font's expansion factor using a float value. The problem only occurs where two ranges with different font sizes meet, and this is a graphical rendering issue that cannot be overridden. But if you explicitly zero out the expansion factor, or even apply a small negative value, the gaps will not be noticeable.

attributedString.addAttribute(.expansion, value: NSNumber(value: 0), range: nsText.range(of: "Hello + World!"))

https://developer.apple.com/documentation/foundation/nsattributedstring/key/1524652-expansion?language=objc__5



Related Topics



Leave a reply



Submit