173

I have a custom font I want to use for everything displaying text in my app, labels, text views etc.

Is there a way to set the default font (labels by default use SystemFont) for the whole app?

3
  • 7
    Having massively looked in to this woe. We have honestly found the simplest thing to do is just make a (trivial) new class, for each control. So for UIButton, make SJButton. Don't forget to override both initWithFrame and initWithCode. For each control (say UIButton, etc) set the colours or whatever you like. Carefully pick up say the size (i.e. that will be the size SET ON THE STORYBOARD) in the int code, and then (as you prefer) use that size (and set, say, the font, colour - whatever). It's only a few lines of code, is incredibly tidy, and saves you vast time in the long run.
    – Fattie
    Commented Jul 28, 2014 at 13:04
  • @JoeBlow Thanks for posting your findings - was about to spend time looking to answer that myself
    – Jared Kove
    Commented Aug 11, 2016 at 10:07
  • @jj- Right. Don't forget too you certainly MUST use IBDesignable these days. Hope it helps. Also consider this interesting QA: stackoverflow.com/a/38000466/294884
    – Fattie
    Commented Aug 11, 2016 at 10:19

17 Answers 17

160

It seems to be possible in iOS 5 using the UIAppearance proxy.

 [[UILabel appearance] setFont:[UIFont fontWithName:@"YourFontName" size:17.0]];

That will set the font to be whatever your custom font is for all UILabels in your app. You'll need to repeat it for each control (UIButton, UILabel, etc.).

Remember you'll need to put the UIAppFonts value in your info.plist and include the name of the font you're including.

14
  • 48
    Thanks for the response. I was able to get this to work. Do you know if there is a way to specify the font without specifying the font size? I have labels in my app that don't share the same font size.
    – Brandon
    Commented Jan 26, 2012 at 19:10
  • 23
    Can I do this without overriding the point size of every instance? Commented May 17, 2012 at 9:51
  • 17
    setFont: method is deprecated
    – Anand
    Commented Oct 30, 2012 at 10:53
  • 12
    @Anand are you sure about this? I don't see it marked as deprecated in UILabel. It is deprecated for UIButton but it using the font for the titleLabel property instead which is a UILabel, so just setting the font with the appearance proxy for UILabel should be fine. Commented Feb 23, 2013 at 23:43
  • 6
    @Anand it is not deprecated for UILabel. Commented Mar 20, 2013 at 1:05
139

Swift 5

Base on Fábio Oliveira's answer (https://stackoverflow.com/a/23042694/2082851), I make my own swift 4.

In short, this extension exchanges default functions init(coder:), systemFont(ofSize:), boldSystemFont(ofSize:), italicSystemFont(ofSize:) with my custom methods.

Note that it's not fully implement, but you can exchange more methods base on my implementation.

import UIKit

struct AppFontName {
    static let regular = "CourierNewPSMT"
    static let bold = "CourierNewPS-BoldMT"
    static let italic = "CourierNewPS-ItalicMT"
}

extension UIFontDescriptor.AttributeName {
    static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")
}

extension UIFont {
    static var isOverrided: Bool = false

    @objc class func mySystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: AppFontName.regular, size: size)!
    }

    @objc class func myBoldSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: AppFontName.bold, size: size)!
    }

    @objc class func myItalicSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: AppFontName.italic, size: size)!
    }

    @objc convenience init(myCoder aDecoder: NSCoder) {
        guard
            let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor,
            let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String else {
                self.init(myCoder: aDecoder)
                return
        }
        var fontName = ""
        switch fontAttribute {
        case "CTFontRegularUsage":
            fontName = AppFontName.regular
        case "CTFontEmphasizedUsage", "CTFontBoldUsage":
            fontName = AppFontName.bold
        case "CTFontObliqueUsage":
            fontName = AppFontName.italic
        default:
            fontName = AppFontName.regular
        }
        self.init(name: fontName, size: fontDescriptor.pointSize)!
    }

    class func overrideInitialize() {
        guard self == UIFont.self, !isOverrided else { return }

        // Avoid method swizzling run twice and revert to original initialize function
        isOverrided = true

        if let systemFontMethod = class_getClassMethod(self, #selector(systemFont(ofSize:))),
            let mySystemFontMethod = class_getClassMethod(self, #selector(mySystemFont(ofSize:))) {
            method_exchangeImplementations(systemFontMethod, mySystemFontMethod)
        }

        if let boldSystemFontMethod = class_getClassMethod(self, #selector(boldSystemFont(ofSize:))),
            let myBoldSystemFontMethod = class_getClassMethod(self, #selector(myBoldSystemFont(ofSize:))) {
            method_exchangeImplementations(boldSystemFontMethod, myBoldSystemFontMethod)
        }

        if let italicSystemFontMethod = class_getClassMethod(self, #selector(italicSystemFont(ofSize:))),
            let myItalicSystemFontMethod = class_getClassMethod(self, #selector(myItalicSystemFont(ofSize:))) {
            method_exchangeImplementations(italicSystemFontMethod, myItalicSystemFontMethod)
        }

        if let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:))), // Trick to get over the lack of UIFont.init(coder:))
            let myInitCoderMethod = class_getInstanceMethod(self, #selector(UIFont.init(myCoder:))) {
            method_exchangeImplementations(initCoderMethod, myInitCoderMethod)
        }
    }
}


class AppDelegate: UIResponder, UIApplicationDelegate {
    // Avoid warning of Swift
    // Method 'initialize()' defines Objective-C class method 'initialize', which is not guaranteed to be invoked by Swift and will be disallowed in future versions
    override init() {
        super.init()
        UIFont.overrideInitialize()
    }
    ...
}
20
  • 2
    best answer!! automatically override the system font, brilliant
    – Kappe
    Commented Nov 18, 2016 at 19:11
  • 2
    If somebody has problems with the "NSCTFontUIUsageAttribute" line: if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String { did the trick for me.
    – DrDirk
    Commented Nov 7, 2017 at 19:23
  • 1
    does not seems to work with UILabels that set text-style (bold,headline,title, etc)... only works with font that have a specific size and system font set. @nahung89
    – Aviran
    Commented Aug 7, 2018 at 12:10
  • 1
    This also switches some system UI fonts. For example, the keyboard suggestion list and the action sheet. Don't know if this will cause Apple to reject the app Commented Nov 21, 2018 at 1:35
  • 1
    Its been a year since this answer has been posted. Does anyone have a more "native" Apple way to achieve this? Commented May 7, 2019 at 18:01
75

There is also another solution which will be to override systemFont.

Just create a category

UIFont+SystemFontOverride.h

#import <UIKit/UIKit.h>

@interface UIFont (SystemFontOverride)
@end

UIFont+SystemFontOverride.m

@implementation UIFont (SystemFontOverride)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

+ (UIFont *)boldSystemFontOfSize:(CGFloat)fontSize {
    return [UIFont fontWithName:@"fontName" size:fontSize];
}

+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
    return [UIFont fontWithName:@"fontName" size:fontSize];
}

#pragma clang diagnostic pop

@end

This will replace the default implementation and most UIControls use systemFont.

12
  • 1
    Is this within apple guidelines?
    – Rambatino
    Commented Aug 22, 2013 at 13:48
  • It's more a hack. I haven't add my app register with this hack, as it's not using any private methods. If you want a more robust solution, I also suggest you to check this: github.com/0xced/FontReplacer
    – Hugues BR
    Commented Aug 22, 2013 at 17:28
  • 2
    This is fine. Apple just don't want you using undocumented functions. You are allowed to “swizzle” methods that are public.
    – mxcl
    Commented Feb 6, 2014 at 20:56
  • 4
    When a category has methods with the same signature as the class it's extending the behaviour is undefined. To replace class methods you should use method swizzling (which also isn't a good idea).
    – GreatWiz
    Commented May 14, 2014 at 15:06
  • 1
    As others have pointed out, this solution, while likely to be effective the majority of the time, is technically introducing the potential for undefined behavior. If you don't feel like risking it, method swizzling might be a better option. The answer here provides the same solution via swizzling: stackoverflow.com/questions/19542942/… Commented Jul 31, 2015 at 17:46
70

If you're using Swift, you can create a UILabel extension:

extension UILabel {

    @objc var substituteFontName : String {
        get { return self.font.fontName }
        set { self.font = UIFont(name: newValue, size: self.font.pointSize) }
    }

}

And then where you do your appearance proxying:

UILabel.appearance().substituteFontName = applicationFont

There is equivalent Objective-C code using UI_APPEARANCE_SELECTOR on a property with the name substituteFontName.

Addition

For the case where you'd want to set bold and regular fonts separately:

extension UILabel {

    @objc var substituteFontName : String {
        get { return self.font.fontName }
        set { 
            if self.font.fontName.range(of:"Medium") == nil { 
                self.font = UIFont(name: newValue, size: self.font.pointSize)
            }
        }
    }

    @objc var substituteFontNameBold : String {
        get { return self.font.fontName }
        set { 
            if self.font.fontName.range(of:"Medium") != nil { 
                self.font = UIFont(name: newValue, size: self.font.pointSize)
            }
        }
    }
}

Then for your UIAppearance proxies:

UILabel.appearance().substituteFontName = applicationFont
UILabel.appearance().substituteFontNameBold = applicationFontBold

Note: if you're finding that the bold substitution isn't working, it's possible the default font name doesn't contain "Medium". Switch out that string for another match as needed (thanks to Mason in the comments below) .

10
  • One downside to this that I've found is that when I initiate alerts with UIAlertController, the button with the .Cancel style is the same as the button with the .Default style (at least when using GillSans). Whereas normally .Cancel would be a regular weight font, and .Default would be bold. Any ideas? Commented Apr 26, 2015 at 15:26
  • Sorry, I meant .Cancel labels would normally be bold, and Default would normally be regular weight. Commented Apr 26, 2015 at 15:40
  • 2
    @MasonG.Zhwiti In that case, I'd likely set up the UILabel extension to take an additional font name for bold. Then in the set do a check to see if "Bold" is in the font name and ignore the set in one case, and use it in the other. I'll edit and add an example. Commented May 7, 2015 at 12:03
  • @SandyChapman Thanks! I'm trying this new technique, and it makes sense, but it doesn't seem to be working for me. I'm using GillSans and GillSans-Bold on iOS 8.3 simulator. Have you tested this technique? Commented May 7, 2015 at 16:35
  • 2
    @SandyChapman I figured out what's going on. The default fonts for iOS 8 tend to be either HelveticaNeueInterface-Regular or (for bold) HelveticaNeueInterface-MediumP4. So looking for "Bold" was never matching anything. I changed it to rangeOfString("Medium") and it worked. Commented May 9, 2015 at 17:03
22

Developing from Hugues BR answer but using method swizzling I've arrived to a solution that is successfully changing all the fonts to a desired font in my app.

An approach with Dynamic Type should be what you should look for on iOS 7. The following solution is not using Dynamic Type.


Notes:

  • the code below, in its presented state, was never submitted to Apple approval;
  • there is a shorter version of it that passed Apple submission, that is without the - initWithCoder: override. However that won't cover all the cases;
  • the following code is present in a class I use to set the style of my app which is included by my AppDelegate class thus being available everywhere and to all UIFont instances;
  • I'm using Zapfino here just to make the changes much more visible;
  • any improvement you may find to this code is welcome.

This solution uses two different methods to achieve the final result. The first is override the UIFont class methods + systemFontWithSize: and similar with ones that use my alternatives (here I use "Zapfino" to leave no doubts that the replacement was successful).

The other method is to override - initWithCoder: method on UIFont to replace any occurrence of CTFontRegularUsage and similar by my alternatives. This last method was necessary because I've found that UILabel objects encoded in NIB files don't check the + systemFontWithSize: methods to get their system font and instead encode them as UICTFontDescriptor objects. I've tried to override - awakeAfterUsingCoder: but somehow it was getting called for every encoded object in my storyboard and causing crashes. Overriding - awakeFromNib wouldn't allow me to read the NSCoder object.

#import <objc/runtime.h>

NSString *const FORegularFontName = @"Zapfino";
NSString *const FOBoldFontName = @"Zapfino";
NSString *const FOItalicFontName = @"Zapfino";

#pragma mark - UIFont category
@implementation UIFont (CustomFonts)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+ (void)replaceClassSelector:(SEL)originalSelector withSelector:(SEL)modifiedSelector {
    Method originalMethod = class_getClassMethod(self, originalSelector);
    Method modifiedMethod = class_getClassMethod(self, modifiedSelector);
    method_exchangeImplementations(originalMethod, modifiedMethod);
}

+ (void)replaceInstanceSelector:(SEL)originalSelector withSelector:(SEL)modifiedSelector {
    Method originalDecoderMethod = class_getInstanceMethod(self, originalSelector);
    Method modifiedDecoderMethod = class_getInstanceMethod(self, modifiedSelector);
    method_exchangeImplementations(originalDecoderMethod, modifiedDecoderMethod);
}

+ (UIFont *)regularFontWithSize:(CGFloat)size
{
    return [UIFont fontWithName:FORegularFontName size:size];
}

+ (UIFont *)boldFontWithSize:(CGFloat)size
{
    return [UIFont fontWithName:FOBoldFontName size:size];
}

+ (UIFont *)italicFontOfSize:(CGFloat)fontSize
{
    return [UIFont fontWithName:FOItalicFontName size:fontSize];
}

- (id)initCustomWithCoder:(NSCoder *)aDecoder {
    BOOL result = [aDecoder containsValueForKey:@"UIFontDescriptor"];

    if (result) {
        UIFontDescriptor *descriptor = [aDecoder decodeObjectForKey:@"UIFontDescriptor"];

        NSString *fontName;
        if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontRegularUsage"]) {
            fontName = FORegularFontName;
        }
        else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontEmphasizedUsage"]) {
            fontName = FOBoldFontName;
        }
        else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontObliqueUsage"]) {
            fontName = FOItalicFontName;
        }
        else {
            fontName = descriptor.fontAttributes[@"NSFontNameAttribute"];
        }

        return [UIFont fontWithName:fontName size:descriptor.pointSize];
    }

    self = [self initCustomWithCoder:aDecoder];

    return self;
}

+ (void)load
{
    [self replaceClassSelector:@selector(systemFontOfSize:) withSelector:@selector(regularFontWithSize:)];
    [self replaceClassSelector:@selector(boldSystemFontOfSize:) withSelector:@selector(boldFontWithSize:)];
    [self replaceClassSelector:@selector(italicSystemFontOfSize:) withSelector:@selector(italicFontOfSize:)];

    [self replaceInstanceSelector:@selector(initWithCoder:) withSelector:@selector(initCustomWithCoder:)];
}
#pragma clang diagnostic pop

@end
7
  • How you use this implementation on iOS6 which dont have UIFontDescriptor Commented Apr 30, 2014 at 14:27
  • I've used the decoder key "UIFontTraits" to check if the font provided is bold or italic and replace it with my own variations. Got it from this gist here gist.github.com/Daij-Djan/5046612. Commented May 5, 2014 at 13:12
  • Thanks for answer i used another solution for now. I will check it when i need it again :) Commented May 6, 2014 at 7:30
  • 2
    thank @FábioOliveira, it works like a charm! Just one more thing that you need to put #import <objc/runtime.h> on the header, otherwise you will get error by using 'Method' class (error I get in XCode 6)
    – nahung89
    Commented Oct 10, 2014 at 6:12
  • For some reason, on iOS 8, modals (UIAlertController) don't change font.
    – Randomblue
    Commented Apr 16, 2015 at 5:13
14

To complete Sandy Chapman's answer, here is a solution in Objective-C (put this category anywhere you want to change UILabel Appearance):

@implementation UILabel (FontOverride)
- (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR {
    self.font = [UIFont fontWithName:name size:self.font.pointSize];
}
@end

The interface file, should have this method declared publicly to be used later from places like your app delegate:

@interface UILabel (FontOverride)
  - (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR;
@end

Then, you can change the Appearance with:

[[UILabel appearance] setSubstituteFontName:@"SourceSansPro-Light"];
4
  • 1
    Hi, do you mean "anywhere", that code would have to be added in every view controller, and have every UILabel used in the controller, where you wished to change the font?
    – Jules
    Commented Jun 20, 2015 at 19:17
  • No, you have to put this code once, anywhere in your project ; in your appdelegate for instance. Commented Jun 22, 2015 at 11:51
  • 1
    @DamienDebin I want to use bold font for bold but this changes bold to light. Any way around?
    – Zeeshan
    Commented Oct 19, 2015 at 11:23
  • Actually, it works, But should it be "Category" or "Extention"? The difference explained here: stackoverflow.com/questions/7136124/… Commented Dec 8, 2015 at 19:42
5

I created my own conversion of typography for Swift 4 after reviewing a few posts, it covers most of the cases, such as:

1st Add fonts to project estructure and to .plist file (with the same name):

<key>UIAppFonts</key>
<array>
    <string>Typo-Light.ttf</string>
    <string>Typo-Regular.ttf</string>
    <string>Typo-Semibold.ttf</string>
    <string>Typo-LightItalic.ttf</string>
</array>

Then

struct Resources {

    struct Fonts {
        //struct is extended in Fonts
    }
}

extension Resources.Fonts {

    enum Weight: String {
        case light = "Typo-Light"
        case regular = "Typo-Regular"
        case semibold = "Typo-Semibold"
        case italic = "Typo-LightItalic"
    }
}

extension UIFontDescriptor.AttributeName {
    static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")
}

extension UIFont {

    @objc class func mySystemFont(ofSize: CGFloat, weight: UIFont.Weight) -> UIFont {
        switch weight {
        case .semibold, .bold, .heavy, .black:
            return UIFont(name: Resources.Fonts.Weight.semibold.rawValue, size: ofSize)!

        case .medium, .regular:
            return UIFont(name: Resources.Fonts.Weight.regular.rawValue, size: ofSize)!

        default:
            return UIFont(name: Resources.Fonts.Weight.light.rawValue, size: ofSize)!
        }
    }

    @objc class func mySystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: Resources.Fonts.Weight.light.rawValue, size: size)!
    }

    @objc class func myBoldSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: Resources.Fonts.Weight.semibold.rawValue, size: size)!
    }

    @objc class func myItalicSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: Resources.Fonts.Weight.italic.rawValue, size: size)!
    }

    @objc convenience init(myCoder aDecoder: NSCoder) {
        guard
            let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor,
            let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String else {
                self.init(myCoder: aDecoder)
                return
        }
        var fontName = ""
        switch fontAttribute {
        case "CTFontRegularUsage", "CTFontMediumUsage":
            fontName = Resources.Fonts.Weight.regular.rawValue
        case "CTFontEmphasizedUsage", "CTFontBoldUsage", "CTFontSemiboldUsage","CTFontHeavyUsage", "CTFontBlackUsage":
            fontName = Resources.Fonts.Weight.semibold.rawValue
        case "CTFontObliqueUsage":
            fontName = Resources.Fonts.Weight.italic.rawValue
        default:
            fontName = Resources.Fonts.Weight.light.rawValue
        }
        self.init(name: fontName, size: fontDescriptor.pointSize)!
    }

    class func overrideDefaultTypography() {
        guard self == UIFont.self else { return }

        if let systemFontMethodWithWeight = class_getClassMethod(self, #selector(systemFont(ofSize: weight:))),
            let mySystemFontMethodWithWeight = class_getClassMethod(self, #selector(mySystemFont(ofSize: weight:))) {
            method_exchangeImplementations(systemFontMethodWithWeight, mySystemFontMethodWithWeight)
        }

        if let systemFontMethod = class_getClassMethod(self, #selector(systemFont(ofSize:))),
            let mySystemFontMethod = class_getClassMethod(self, #selector(mySystemFont(ofSize:))) {
            method_exchangeImplementations(systemFontMethod, mySystemFontMethod)
        }

        if let boldSystemFontMethod = class_getClassMethod(self, #selector(boldSystemFont(ofSize:))),
            let myBoldSystemFontMethod = class_getClassMethod(self, #selector(myBoldSystemFont(ofSize:))) {
            method_exchangeImplementations(boldSystemFontMethod, myBoldSystemFontMethod)
        }

        if let italicSystemFontMethod = class_getClassMethod(self, #selector(italicSystemFont(ofSize:))),
            let myItalicSystemFontMethod = class_getClassMethod(self, #selector(myItalicSystemFont(ofSize:))) {
            method_exchangeImplementations(italicSystemFontMethod, myItalicSystemFontMethod)
        }

        if let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:))),
            let myInitCoderMethod = class_getInstanceMethod(self, #selector(UIFont.init(myCoder:))) {
            method_exchangeImplementations(initCoderMethod, myInitCoderMethod)
        }
    }
}

Finally call to created method at Appdelegate like next:

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

        UIFont.overrideDefaultTypography()
        return true
    }
}
3
  • @sheshnath can you give us more crash info ?
    – Javi AP
    Commented Jun 13, 2019 at 14:54
  • 1
    sorry mistake was from my side, font was not listed in info.plist
    – Sheshnath
    Commented Jun 14, 2019 at 9:44
  • @midhunp Could you be more explicit so that it is not working for you?. It works well for me with bold typeface.
    – Javi AP
    Commented Jul 24, 2019 at 14:46
4

COMMENT FOR SWIFT 3.0 AND SWIFT WARNING

You can remove the warning message in line:

let initCoderMethod = class_getInstanceMethod(self, Selector("initWithCoder:"))

By replacing it with:

let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:)))
1
  • Lol. I didn't know that Swift allow using this. Btw, I will update it to above answer. Thanks you @ucotta!
    – nahung89
    Commented Apr 3, 2017 at 8:45
4

For Swift 5

All the above answers are correct but i have done in little different way that is according to device size. Here, in ATFontManager class, i have made default font size which is define at the top of the class as defaultFontSize, this is the font size of iphone plus and you can changed according to your requirement.

class ATFontManager: UIFont{
    
    class func setFont( _ iPhone7PlusFontSize: CGFloat? = nil,andFontName fontN : String = FontName.helveticaNeue) -> UIFont{
        
        let defaultFontSize : CGFloat = 16
        
        switch ATDeviceDetector().screenType {
            
        case .iPhone4:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize - 5)!
            }
            return UIFont(name: fontN, size: defaultFontSize - 5)!
            
        case .iPhone5:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize - 3)!
            }
            return UIFont(name: fontN, size: defaultFontSize - 3)!
            
        case .iPhone6AndIphone7, .iPhoneUnknownSmallSize:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize - 2)!
            }
            return UIFont(name: fontN, size: defaultFontSize - 2)!
            
        case .iPhone6PAndIPhone7P, .iPhoneUnknownBigSize:
            
            return UIFont(name: fontN, size: iPhone7PlusFontSize ?? defaultFontSize)!
        case .iPhoneX, .iPhoneXsMax:
            
            return UIFont(name: fontN, size: iPhone7PlusFontSize ?? defaultFontSize)!
          
        case .iPadMini:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize + 2)!
            }
            return UIFont(name: fontN, size: defaultFontSize + 2)!
            
        case .iPadPro10Inch:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize + 4)!
            }
            return UIFont(name: fontN, size: defaultFontSize + 4)!
            
        case .iPadPro:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize + 6)!
            }
            return UIFont(name: fontN, size: defaultFontSize + 6)!
            
        case .iPadUnknownSmallSize:
            
            return UIFont(name: fontN, size: defaultFontSize + 2)!
            
        case .iPadUnknownBigSize:
            
            return UIFont(name: fontN, size: defaultFontSize + 4)!
            
        default:
            
            return UIFont(name: fontN, size: iPhone7PlusFontSize ?? 16)!
        }
    }
}
     

I have added certain font name, for more you can add the font name and type here.

   enum FontName : String {
        case HelveticaNeue = "HelveticaNeue"
        case HelveticaNeueUltraLight = "HelveticaNeue-UltraLight"
        case HelveticaNeueBold = "HelveticaNeue-Bold"
        case HelveticaNeueBoldItalic = "HelveticaNeue-BoldItalic"
        case HelveticaNeueMedium = "HelveticaNeue-Medium"
        case AvenirBlack = "Avenir-Black"
        case ArialBoldMT = "Arial-BoldMT"
        case HoeflerTextBlack = "HoeflerText-Black"
        case AMCAPEternal = "AMCAPEternal"
    }

This class refers to device detector in order to provide appropriate font size according to device.

class ATDeviceDetector {
    
    var iPhone: Bool {
        
        return UIDevice().userInterfaceIdiom == .phone
    }
    
    var ipad : Bool{
        
        return UIDevice().userInterfaceIdiom == .pad
    }
    
    let isRetina = UIScreen.main.scale >= 2.0
    
    
    enum ScreenType: String {
        
        case iPhone4
        case iPhone5
        case iPhone6AndIphone7
        case iPhone6PAndIPhone7P
        case iPhoneX
        
        case iPadMini
        case iPadPro
        case iPadPro10Inch
        
        case iPhoneOrIPadSmallSizeUnknown
        case iPadUnknown
        case unknown
    }
    
    
    struct ScreenSize{
        
        static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
        static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
        static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH,ScreenSize.SCREEN_HEIGHT)
        static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH,ScreenSize.SCREEN_HEIGHT)
    }
    
    
    var screenType: ScreenType {
        
        switch ScreenSize.SCREEN_MAX_LENGTH {
            
        case 0..<568.0:
            return .iPhone4
        case 568.0:
            return .iPhone5
        case 667.0:
            return .iPhone6AndIphone7
        case 736.0:
            return .iPhone6PAndIPhone7P
        case 812.0:
            return .iPhoneX
        case 568.0..<812.0:
            return .iPhoneOrIPadSmallSizeUnknown
        case 1112.0:
            return .iPadPro10Inch
        case 1024.0:
            return .iPadMini
        case 1366.0:
            return .iPadPro
        case 812.0..<1366.0:
            return .iPadUnknown
        default:
            return .unknown
        }
    }
}

How to use. Hope it will help.

//for default 
label.font = ATFontManager.setFont()

//if you want to provide as your demand. Here **iPhone7PlusFontSize** variable is denoted as font size for *iphone 7plus and iphone 6 plus*, and it **ATFontManager** class automatically handle.
label.font = ATFontManager.setFont(iPhone7PlusFontSize: 15, andFontName: FontName.HelveticaNeue.rawValue)
3

None of these solutions works universally throughout the app. One thing I found to help manage the fonts in Xcode is opening the Storyboard as Source code (Control-click storyboard in Files navigator > "Open as" > "Source"), and then doing a find-and-replace.

3

Font type always be set in code and nib/storyboard.

For the code,just like Hugues BR said,do it in catagory can solve the problem.

For the nib/storyboard,we can Method Swizzling awakeFromNib to change font type since UI element from nib/storyboard always call it before show in the screen.

I suppose you know Aspects.It's a library for AOP programing,based on Method Swizzling. We create catagory for UILabel,UIButton,UITextView to implement it.

UILabel:

#import "UILabel+OverrideBaseFont.h"
#import "Aspects.h"

@implementation UILabel (OverrideBaseFont)

+ (void)load {
    [[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
        UILabel* instance = [aspectInfo instance];
        UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:instance.font.pointSize];
        instance.font = font;
    }error:nil];
}

@end

UIButton:

#import "UIButton+OverrideBaseFont.h"
#import "Aspects.h"

@implementation UIButton (OverrideBaseFont)

+ (void)load {
    [[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
        UIButton* instance = [aspectInfo instance];
        UILabel* label = instance.titleLabel;
        UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:label.font.pointSize];
        instance.titleLabel.font = font;
    }error:nil];
}

@end

UITextField:

#import "UITextField+OverrideBaseFont.h"
#import "Aspects.h"

@implementation UITextField (OverrideBaseFont)

+ (void)load {
    [[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
        UITextField* instance = [aspectInfo instance];
        UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:instance.font.pointSize];
        instance.font = font;
    }error:nil];
}

@end

UITextView:

#import "UITextView+OverrideBaseFont.h"
#import "Aspects.h"

@implementation UITextView (OverrideBaseFont)

+ (void)load {
    [[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
        UITextView* instance = [aspectInfo instance];
        UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:instance.font.pointSize];
        instance.font = font;
    }error:nil];
}

@end

That's all,you can change HelveticaNeue-light to a macro with your font name.

2

Probably not, you will probably have the set the font on your control yourself, but you can make the process easier by centralizing where you get the font types from, for example have the app delegate or some other common class have a method that returns the font, and anything needing to set the font can call that method, that will help in case you need to change your font, youd change it in one place rather than everywhere you set the fonts...Another alternative can be to make subclasses of your UI Elements that will automatically set the font, but that might be overkill..

3
  • for the record, this is what I did, but @Randall needed the rep, and provided a good answer. I just need to support less than 5.0
    – Sam Jarman
    Commented Jan 3, 2012 at 7:40
  • 4
    I disagree with what you did. The answer you selected is not valid when your question is tagged iphone-sdk-4.0. Commented Apr 27, 2012 at 13:08
  • @Sam Jarman, Randall's answer below is correct - can you mark it that way for future visitors?
    – Bill
    Commented Dec 4, 2013 at 15:08
2

For Xamarin.iOS inside AppDelegate's FinishedLaunching() put code like this :-

UILabel.Appearance.Font= UIFont.FromName("Lato-Regular", 14);

set font for the entire application and Add 'UIAppFonts' key on Info.plist , the path should be the path where your font file .ttf is situated .For me it was inside 'fonts' folder in my project.

<key>UIAppFonts</key>
    <array>
        <string>fonts/Lato-Regular.ttf</string>
    </array>
1
  • 1
    this works, but has no use - because now all the text in your app is of the same size 14... There's probably no way to override it in such way that it will have it's original elements font size
    – Async-
    Commented Feb 3, 2021 at 13:42
2

As @Randall in his answer mentioned iOS 5.0+ UIAppearance proxy can be used to customize the appearance of all instances of a class read more.

UILabel.appearance().font = .systemFont(ofSize: 17, weight: .regular)
1

NUI is an alternative to the UIAppearance proxy. It gives you control over the font (and many other attributes) of a large number of UI element types throughout your application by simply modifying a style sheet, which can be reused across multiple applications.

After adding a NUILabel class to your labels, you could easily control their font in the style sheet:

LabelFontName    String    Helvetica

If you have labels with different font sizes, you could control their sizes using NUI's Label, LargeLabel, and SmallLabel classes, or even quickly create your own classes.

1

Am using like this type of font class in swift. Using font extension class.

enum FontName: String {

  case regular      = "Roboto-Regular"

}

//MARK: - Set Font Size
enum FontSize: CGFloat {
    case size = 10

}
extension UIFont {

    //MARK: - Bold Font
  class var regularFont10: UIFont {
        return UIFont(name: FontName.regular.rawValue, size:FontSize.size.rawValue )!
    }
}
-1

We have achieved the same in Swift -Xcode 7.2 using Parent View Controller and Child view controller (Inheritance).

File - New - Cocoa Touch class - ParentViewController.

    import UIKit
    import Foundation

    class ParentViewController: UIViewController {

        var appUIColor:UIColor = UIColor.redColor()
        var appFont:UIFont = UIFont(name: "Copperplate", size: 20)!

        override func viewDidLoad() {
            super.viewDidLoad()
        }
        func addStatusBar()
        {
            let view = UIView(frame:
                CGRect(x: 0.0, y: 0.0, width: UIScreen.mainScreen().bounds.size.width, height: 20.0)
            )
            view.backgroundColor = appUIColor
            self.view.addSubview(view)
        }
    }    

Make child view controllers and associate with a StoryBoard VC, add a textLabel.

    import UIKit

    class FontTestController: ParentViewController {
        @IBOutlet var testLabel: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
            testLabel.font =  appFont
            testLabel.textColor = appUIColor
        }

OR Make a custom UILabel Class(Sub classing method) and associate required labels to it.

import Foundation
import UIKit

class CustomFontLabel: UILabel {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        backgroundColor = ParentViewController().appUIColor
        font = ParentViewController().appFont
        textColor = UIColor.blackColor()
    }
}

Note: The Font and colour declared in Parent VC are implemented in CustomFontLabel . The advantage is we can alter the properties of uilabel/any view all together in some simple changes in Parent VC.

2)'for' looping UIView for sub views. It works only on a particular VC.

    override func viewWillLayoutSubviews() {
            for view in self.view.subviews  {
                if view.isKindOfClass(UITextField) {
                UITextField.appearance().font =  UIFont(name: "Copperplate", size: 20)
                }
                if view.isKindOfClass(UILabel) {
                    UILabel.appearance().font =  UIFont(name: "Copperplate", size: 20)    
                }               
            }       
        }

Not the answer you're looking for? Browse other questions tagged or ask your own question.