10

User from storyboard or programatically can set font weight as regular, semi bold etc.

I want to read weight for any font label.

I tried po label.font.description and font-weight is there and but there is no exposed variable to get weight from font.

Is it possible?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Kumar
  • 1,882
  • 2
  • 27
  • 44

5 Answers5

14

It seems that fontDescriptor.fontAttributes won't return all the attributes of a font. Luckily fontDescriptor.object(forKey: .traits) will, so we can hop onto that.

extension UIFont {
    var weight: UIFont.Weight {
        guard let weightNumber = traits[.weight] as? NSNumber else { return .regular }
        let weightRawValue = CGFloat(weightNumber.doubleValue)
        let weight = UIFont.Weight(rawValue: weightRawValue)
        return weight
    }

    private var traits: [UIFontDescriptor.TraitKey: Any] {
        return fontDescriptor.object(forKey: .traits) as? [UIFontDescriptor.TraitKey: Any]
            ?? [:]
    }
}

and then it's as simple as label.font.weight

(This is fundamentally equivalent to https://stackoverflow.com/a/48688000/1288097 but it uses UIKit APIs)

DeFrenZ
  • 2,172
  • 1
  • 20
  • 19
  • Elegant. I added a var to the extension to convert an IB-defined system font to its monospaceDigit equivalent, something I'd been fighting for a while. Thanks. Can't do code here, but the meat: `return UIFont.monospacedDigitSystemFont(ofSize: self.pointSize, weight: self.weight)` – JLundell Jul 30 '19 at 02:03
12

To get the font weight string name, use the font descriptor and pass in the face attribute.

Swift 4.2

let font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.bold)
let face = font.fontDescriptor.object(forKey: UIFontDescriptorFaceAttribute) as! String
print("face: \(face)")

Swift 3

let font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightBold)
let face = font.fontDescriptor.object(forKey: UIFontDescriptorFaceAttribute) as! String
print("face: \(face)")
Lukas Würzburger
  • 6,543
  • 7
  • 41
  • 75
bbarnhart
  • 6,620
  • 1
  • 40
  • 60
  • 4
    `UIFontDescriptorFaceAttribute` has been renamed to `UIFontDescriptor.AttributeName.face` (or just `.face`) in later versions of Swift. – Dafydd Williams Aug 15 '18 at 00:49
9

Try following sample font extension with Swift 4. (It needs some improvement for all types of font weights)

extension UIFont {

    func getFontWeight() -> UIFont.Weight {
    
        let fontAttributeKey = UIFontDescriptor.AttributeName.init(rawValue: "NSCTFontUIUsageAttribute")
        if let fontWeight = self.fontDescriptor.fontAttributes[fontAttributeKey] as? String {
            switch fontWeight {

            case "CTFontBoldUsage":
                return UIFont.Weight.bold
        
            case "CTFontBlackUsage":
                return UIFont.Weight.black
        
            case "CTFontHeavyUsage":
                return UIFont.Weight.heavy
        
            case "CTFontUltraLightUsage":
                return UIFont.Weight.ultraLight
        
            case "CTFontThinUsage":
                return UIFont.Weight.thin
        
            case "CTFontLightUsage":
                return UIFont.Weight.light
        
            case "CTFontMediumUsage":
                return UIFont.Weight.medium
        
            case "CTFontDemiUsage":
                return UIFont.Weight.semibold
        
            case "CTFontRegularUsage":
                return UIFont.Weight.regular

            default:
                return UIFont.Weight.regular
            }
        }
        
    return UIFont.Weight.regular
}

Try with label:

let label = UILabel()
var fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.bold)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.black)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.heavy)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.ultraLight)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.thin)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.light)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.medium)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.semibold)
fontWeight = label.font.getFontWeight()
print("fontWeight - \(fontWeight)")

Here is Apple document for list of Font Weights

The value of this weight is an NSNumber object. The valid value range is from -1.0 to 1.0. The value of 0.0 corresponds to the regular or medium font weight. You can also use a font weight constant to specify a particular weight.

Ely
  • 8,259
  • 1
  • 54
  • 67
Krunal
  • 77,632
  • 48
  • 245
  • 261
3

It seems that there is no direct way to get it. As a workaround, You could get an indication of what's the weight of the font as follows:

let labelFont = label.font as CTFont
if let fontTraits = CTFontCopyTraits(labelFont) as? [CFString: CFNumber], let fontWeight = fontTraits[kCTFontWeightTrait] {
    print(fontWeight)
}

The UIFont has been casted as CTFont, which generates CFDictionary (by using CTFontCopyTraits(_:)) that contains the value of kCTFontWeightTrait. Note that it would not what is the exact font weight, nevertheless it could be somehow useful to an indication of what is the weight:

Key to access the normalized weight trait from the font traits dictionary. The value returned is a CFNumber representing a float value between -1.0 and 1.0 for normalized weight. The value of 0.0 corresponds to the regular or medium font weight.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
2

You can play around with font's symbolic traits:

// is true when font is bold
label.font.fontDescriptor.symbolicTraits.contains(UIFontDescriptorSymbolicTraits.traitBold)

Check docs for more traits.

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
  • 2
    this is working when I am checking for bold and italic style. But there is no UIFontDescriptorSymbolicTraits for semibold. – Kumar Feb 08 '18 at 15:05