如何修改NSAttributedString全局字体大小且保留其他原有属性?
NSAttributedString 统一修改字号且保留原有属性的实现方案
核心逻辑:遍历富文本内所有配置了字体属性的区间,基于原字体的描述符生成仅字号变更的新字体替换原有字体属性,其余所有属性(字重、颜色、下划线、段落样式、字间距、链接等)完全保留,不会被篡改。
代码实现
Swift 实现
给NSAttributedString增加扩展方法:
import UIKit extension NSAttributedString { func resizingFont(to targetSize: CGFloat) -> NSAttributedString { let mutableContent = NSMutableAttributedString(attributedString: self) let fullRange = NSRange(location: 0, length: mutableContent.length) // 遍历所有字体属性的有效区间 mutableContent.enumerateAttribute( .font, in: fullRange, options: .longestEffectiveRangeNotRequired ) { originalFont, range, _ in guard let font = originalFont as? UIFont else { return } // 保留原字体全部特征(字重、字体族、斜体/粗体标记等),仅替换字号 let newFont = UIFont(descriptor: font.fontDescriptor, size: targetSize) mutableContent.addAttribute(.font, value: newFont, range: range) } return mutableContent } }
需要设置字号为20时直接调用即可:
let finalAttrStr = yourOriginalAttrStr.resizingFont(to: 20)
Objective-C 实现
#import <UIKit/UIKit.h> @interface NSAttributedString (AZFontResize) - (NSAttributedString *)az_resizeFontToSize:(CGFloat)targetSize; @end @implementation NSAttributedString (AZFontResize) - (NSAttributedString *)az_resizeFontToSize:(CGFloat)targetSize { NSMutableAttributedString *mutableContent = [[NSMutableAttributedString alloc] initWithAttributedString:self]; NSRange fullRange = NSMakeRange(0, self.length); [mutableContent enumerateAttribute:NSFontAttributeName inRange:fullRange options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(id value, NSRange range, BOOL *stop) { if (![value isKindOfClass:[UIFont class]]) return; UIFont *originalFont = (UIFont *)value; UIFont *newFont = [UIFont fontWithDescriptor:originalFont.fontDescriptor size:targetSize]; [mutableContent addAttribute:NSFontAttributeName value:newFont range:range]; }]; return [mutableContent copy]; } @end
macOS 平台适配:将代码中
UIFont替换为NSFont即可,逻辑完全通用。
避坑说明
- 不要直接给富文本全范围调用
addAttribute:value:range:设置统一字体,这种写法会覆盖所有子区间原本的字体差异,比如原本的粗体、斜体、自定义字体会全部被重置。 - 优先使用
enumerateAttribute针对字体属性做遍历,不要全量遍历所有属性,避免不必要的性能损耗,也不会误修改其他非字体属性。 - 基于原字体的
fontDescriptor生成新字体是保留原有字体样式的关键,不要直接用UIFont.systemFont(ofSize:)这类方法生成新字体,否则会丢失原字体的特征。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

