NSAttributedString,改变字体整体但保留所有其他属性?

Fat*_*tie 30 nsattributedstring swift

说我有一个NSMutableAttributedString.

该字符串具有各种格式的格式:

这是一个例子:

这个字符串在iOS中很难改变 ,真的很糟糕.

但是,字体本身不是您想要的字体.

我想要

将每个字符更改为特定字体(例如,Avenir)

但,

在各个地方保留整个字符串中出现的其他每个属性(粗体,斜体,颜色等).

你到底怎么这样做?


注意:

如果您在整个范围内轻松添加属性"Avenir":它只是删除所有其他属性范围,您将丢失所有格式

需要明确的是:不幸的是,属性并非实际上是"附加的".

man*_*mal 46

由于rmaddy的答案对我f.fontDescriptor.withFace(font.fontName)不起作用(不保留大胆的特征),这里是一个更新的Swift 4版本,还包括颜色更新:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记

问题f.fontDescriptor.withFace(font.fontName)在于它删除了象征性特征italic,bold或者compressed,因为它会因某种原因覆盖那些具有该字体的默认特征的特征.为什么这一点完全无法实现,甚至可能是苹果公司的疏忽; 或者它"不是一个错误,而是一个功能",因为我们免费获得新字体的特征.

所以我们要做的是创建一个字体描述符,它具有原始字体字体描述符的符号特征:.withSymbolicTraits(f.fontDescriptor.symbolicTraits).转发到rmaddy我的迭代的初始代码.

我已经在生产应用程序中发送了这个,我们通过解析HTML字符串NSAttributedString.DocumentType.html然后通过上面的扩展名更改字体和颜色.到目前为止没问题.

  • 我在这个实现中发现了一个小错误.如果字符串的任何部分具有NO字体属性,则不会替换它.所以你需要在内部`if`块之后添加`} else {addAttribute(.font,value:font,range:range)}`.如果需要,颜色相同. (3认同)
  • 了解@manmal再次感谢.是的,这是一场噩梦!在某些应用程序中,你必须做iOS真正"不想做"的事情,这就是一个例子. (2认同)

rma*_*ddy 7

这是一个更简单的实现,它保留所有属性,包括所有字体属性,除了它允许您更改字体外观.

请注意,这仅使用传入字体的字体(名称).大小与现有字体保持一致.如果您还想将所有现有字体大小更改f.pointSize为新大小,请更改为font.pointSize.

extension NSMutableAttributedString {
    func replaceFont(with font: UIFont) {
        beginEditing()
        self.enumerateAttribute(.font, in: NSRange(location: 0, length: self.length)) { (value, range, stop) in
            if let f = value as? UIFont {
                let ufd = f.fontDescriptor.withFamily(font.familyName).withSymbolicTraits(f.fontDescriptor.symbolicTraits)!
                let newFont = UIFont(descriptor: ufd, size: f.pointSize)
                removeAttribute(.font, range: range)
                addAttribute(.font, value: newFont, range: range)
            }
        }
        endEditing()
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

let someMutableAttributedString = ... // some attributed string with some font face you want to change
someMutableAttributedString.replaceFont(with: UIFont.systemFont(ofSize: 12))
Run Code Online (Sandbox Code Playgroud)


ing*_*nti 7

我的两分钱是 OSX/AppKit>

extension NSAttributedString {
// replacing font to all:
func setFont(_ font: NSFont, range: NSRange? = nil)-> NSAttributedString {
    let mas = NSMutableAttributedString(attributedString: self)
    let range = range ?? NSMakeRange(0, self.length)
    mas.addAttributes([.font: font], range: range)
    return NSAttributedString(attributedString: mas)
}


// keeping font, but change size:
func setFont(size: CGFloat, range: NSRange? = nil)-> NSAttributedString {
    let mas = NSMutableAttributedString(attributedString: self)
    let range = range ?? NSMakeRange(0, self.length)
    
    
    mas.enumerateAttribute(.font, in: range) { value, range, stop in
        if let font = value as? NSFont {
            let name = font.fontName
            let newFont = NSFont(name: name, size: size)
            mas.addAttributes([.font: newFont!], range: range)
        }
    }
    return NSAttributedString(attributedString: mas)
    
}
Run Code Online (Sandbox Code Playgroud)