0

I want to create a UIFont that is both black in weight (heavier than bold) and italic, without hardcoding any font names or anything.

All my attempts have came up short. You can do it via UIFont.systemFont(ofSize: 15.0, weight: .black) and then applying an italic symbolic trait, but that obviously only works with the system font. (Helvetica and Avenir both for instance come in various font weights that include italic variants.)

Here is my attempt, but it comes up with just a regular weight italic font, not black.

var fontAttributes: [UIFontDescriptor.AttributeName: Any] = [:]
var fontTraits: [UIFontDescriptor.TraitKey: Any] = [:]
fontTraits[.weight] = UIFont.Weight.black // Also hardcoding a number like 0.6 does not work

fontAttributes[.traits] = fontTraits

let descriptor1 = UIFontDescriptor(fontAttributes: fontAttributes)
let descriptor2 = descriptor1.withSymbolicTraits(.traitItalic)!

let font = UIFont(descriptor: descriptor2, size: 19.0)

label.font = font // Sad trombone music. It's just 'regular italic'.
christianselig
  • 405
  • 4
  • 17
  • Does this answer your question? [How do I set bold and italic on UILabel of iPhone/iPad?](https://stackoverflow.com/questions/4713236/how-do-i-set-bold-and-italic-on-uilabel-of-iphone-ipad) – Ptit Xav Oct 27 '21 at 02:49
  • @DougSmith I'm happy to reopen if it's not a proper duplicate, but it seems to me that the technique shown handles any combination of italic and an arbitrary weight. – matt Oct 27 '21 at 14:44
  • @matt Try swapping out .systemFont with UIFont(name: "Avenir", size: 32.0)!, the result no longer seems to work – Doug Smith Oct 27 '21 at 14:46
  • @DougSmith Well that would be because Avenir lacks those variants? I mean to say, nothing will come of nothing. – matt Oct 27 '21 at 14:53
  • @matt Where do you see that? http://iosfonts.com lists Avenir as having a Black Italic version. – Doug Smith Oct 27 '21 at 15:08
  • @DougSmith Well, I'll reopen if you like, it's no big deal. – matt Oct 27 '21 at 15:10
  • Perhaps useful: https://stackoverflow.com/questions/62361819/making-uifont-black-heavy-and-italic – matt Oct 27 '21 at 15:10

1 Answers1

0

I tried a few different routes but this looks promising. It looks like the font name is essential to keep around. It also seems to find the "best" match from existing fonts.

Adapted from https://github.com/wireapp/wire-ios/blob/develop/Wire-iOS/Sources/Helpers/UIFont%2BWeight.swift

import UIKit

public extension UIFont {

    /// Returns a font object that is the same as the receiver but which has the specified weight and symbolic traits
    func with(weight: Weight, symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont {

        var mergedsymbolicTraits = fontDescriptor.symbolicTraits
        mergedsymbolicTraits.formUnion(symbolicTraits)

        var traits = fontDescriptor.fontAttributes[.traits] as? [String: Any] ?? [:]
        traits[kCTFontWeightTrait as String] = weight
        traits[kCTFontSymbolicTrait as String] = mergedsymbolicTraits.rawValue

        var fontAttributes: [UIFontDescriptor.AttributeName: Any] = [:]
        fontAttributes[.family] = familyName
        fontAttributes[.traits] = traits

        return UIFont(descriptor: UIFontDescriptor(fontAttributes: fontAttributes), size: pointSize)
    }
}