Как применить жирный шрифт и курсив к диапазону NSMutableAttributedString?

В последнее время я пытался применить комбинации NSFontAttributes к NSMutableAttributedString, и я просто не могу найти подробное объяснение того, как это сделать, не удаляя другие атрибуты.

Я искал кучу и нашел этот вопрос, касающийся того, как это сделать с HTML, а затем этот вопрос о том, как найти, где текст выделен жирным шрифтом или курсивом, но ничего не о том, как на самом деле это сделать.

В настоящее время я пытаюсь отформатировать строки следующим образом:

Курсив: [mutableAttributedString addAttribute: NSFontAttributeName value:[fontAttributes valueForKey:CXItalicsFontAttributeName] range:r];

Полужирный: [mutableAttributedString addAttribute:NSFontAttributeName value:[fontAttributes valueForKey:CXBoldFontAttributeName] range:r];

Где константы CXItalicsFontAttributeName и CXBoldAttributeName извлекают следующие два значения из словаря:

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

Я знаю, что это не может быть правильным способом форматирования, так как стандартные атрибуты NSAttributedString не включают в себя ItalicsFontAttribute или BoldFontAttribute, но я не могу найти правильный способ сделать это. Кто-нибудь может мне помочь?

Ответ 1

Если вы применяете каждую черту (выделенную жирным шрифтом или курсивом) по отдельности, вы должны убедиться, что диапазоны, выделенные жирным шрифтом и курсивом, не перекрываются, или одна черта заменит другую.

Единственный способ применить черты, выделенные жирным шрифтом и курсивом к диапазону, - это использовать шрифт, выделенный как жирным шрифтом, так и курсивом, и применить обе черты сразу.

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

enter image description here

Ответ 2

В Swift и с использованием расширения:

extension UIFont {

    func withTraits(_ traits: UIFontDescriptorSymbolicTraits) -> UIFont {

        // create a new font descriptor with the given traits
        if let fd = fontDescriptor.withSymbolicTraits(traits) {
            // return a new font with the created font descriptor
            return UIFont(descriptor: fd, size: pointSize)
        }

        // the given traits couldn't be applied, return self
        return self
    }

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

Ответ 3

Лучшим решением моей проблемы до сих пор было использование класса 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

Преимущество здесь в том, что мне больше не нужно создавать отдельные типы шрифтов, и для этого достаточно шрифта из семейства.

Ответ 4

Оформить заказ NSAttributedString.Key.obliqueness. Установка значения этого ключа в значения, отличные от 0, делает текст курсивом с различной степенью.