【问题标题】:How to apply bold and italics to an NSMutableAttributedString range?如何将粗体和斜体应用于 NSMutableAttributedString 范围?
【发布时间】:2016-04-02 16:04:16
【问题描述】:

我最近一直在尝试将 NSFontAttributes 的组合应用于 NSMutableAttributedString,但我根本无法找到关于如何在不删除其他属性的情况下执行此操作的详尽解释。

我搜索了一堆,发现这个 question 与如何使用 HTML 相关,然后是这个 question 关于如何找到粗体或斜体文本,但没有关于如何实际做到这一点。

目前,我尝试将字符串格式化如下:

斜体: [mutableAttributedString addAttribute: NSFontAttributeName value:[fontAttributes valueForKey:CXItalicsFontAttributeName] range:r];

粗体: [mutableAttributedString addAttribute:NSFontAttributeName value:[fontAttributes valueForKey:CXBoldFontAttributeName] range:r];

其中常量CXItalicsFontAttributeNameCXBoldAttributeName 分别从字典中提取以下两个值:

UIFont *italicsFont = [UIFont fontWithName:@"Avenir-BookOblique" size:14.0f];
UIFont *boldFont = [UIFont fontWithName:@"Avenir-Heavy" size:14.0f];

我知道这一定不是格式化的正确方法,因为 NSAttributedString standard attributes 不包含 ItalicsFontAttribute 或 BoldFontAttribute,但我找不到正确的方法来执行此操作。任何人都可以帮助我吗?

【问题讨论】:

    标签: ios objective-c nsstring nsmutableattributedstring


    【解决方案1】:

    在 Swift 中并使用扩展:

    extension UIFont {
    
        func withTraits(_ traits: UIFontDescriptor.SymbolicTraits) -> 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 ])
        }
    }
    

    例子:

    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()) ])
    }
    

    【讨论】:

    • 很好的答案,@nyg
    【解决方案2】:

    详情

    • Swift 5.1,Xcode 11.3.1

    解决方案

    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: [])
    

    完整样本

    不要忘记在此处粘贴解决方案代码

    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)
        }
    }
    

    结果

    【讨论】:

    • 非常有用的解决方案。看到这一点后,我将构建的文本应用程序的计划是只为用户提供同时具有粗体和斜体特征的字体。
    【解决方案3】:

    结帐NSAttributedString.Key.obliqueness。将此键的值设置为0以外的值会使文本斜体的程度不同。

    【讨论】:

    • 这适用于不支持斜体的中文或韩文等字符!谢谢
    【解决方案4】:

    到目前为止,对我的问题的最佳解决方案是利用UIFontDescriptor 类为我遇到的每种情况提供必要的UIFont

    例如,我想使用Avenir-Book 作为我的主要字体,大小为14,我可以创建一个UIFontDescriptor,如下所示:

    UIFontDescriptor *fontDescriptor = [UIFontDescriptor fontDescriptorWithName:@"Avenir-Book" size:14.0f];

    接下来,如果我想获得斜体、粗体或两者的组合,我可以简单地执行以下操作:

    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];
    

    这确实会在打印时产生所需的字体:

    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);
    

    输出:

    Normal Font: Avenir-Book Size: 14
    Italics Font: Avenir-BookOblique
    Bold Font: Avenir-Black
    Bold and Italics Font: Avenir-BlackOblique
    

    这里的好处是我不再需要自己创建单独的字体类型,并且该系列的字体就足够了。

    【讨论】:

      【解决方案5】:

      如果您单独应用每个(粗体或斜体)特征,您需要确保粗体和斜体范围不重叠,否则一个特征会覆盖另一个特征。

      将粗体 斜体特征应用于范围的唯一方法是使用粗体和斜体的字体,并同时应用这两个特征。

      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))
      

      【讨论】:

      • 这种方法似乎不切实际。这意味着我需要创建尽可能多的组合来尝试解决所有情况。我希望避免它。
      • @Owatch 这是a question that asks about enumerating。您仍然需要动态构建字体。没有办法解决这个问题。
      • 我之前选择了您的答案作为解决方案,因为我找不到任何替代方案,但后来找到了更适合我正在寻找的东西,所以我删除了复选标记。我为不一致而道歉。
      • 我最初的问题是在知道 BoldItalicsFont 确实存在的情况下编写的。但是,我误解了这些东西不能说是“分层”的,它们完全是我必须应用的自己的单独字体。我可以看到它不清楚,所以我想如果你认为你的答案最适合目前的问题,我可以再次选择它。
      • 一切都好!不幸的是,没有办法独立于字体应用特征,因为这些特征是特定于每种字体的。
      猜你喜欢
      • 1970-01-01
      • 2016-04-22
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-07
      相关资源
      最近更新 更多