By Sam Jarman


2012-01-03 01:44:57 8 Comments

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?

17 comments

@esesmuedgars 2019-10-16 21:28:17

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

Xcodes auto complete does not show all of the available properties and might throw an error, but you can just type it out and it will compile.

UILabel.apperance().font = UIFont.systemFont(ofSize: 17, weight: .regular)

@Amrit Tiwari 2017-08-10 04:32:56

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)

@ucotta 2017-02-15 01:08:14

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

@nahung89 2017-04-03 08:45:15

Lol. I didn't know that Swift allow using this. Btw, I will update it to above answer. Thanks you @ucotta!

@Damien Debin 2015-04-16 13:50:33

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

@Jules 2015-06-20 19:17:08

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?

@Damien Debin 2015-06-22 11:51:24

No, you have to put this code once, anywhere in your project ; in your appdelegate for instance.

@Xeieshan 2015-10-19 11:23:56

@DamienDebin I want to use bold font for bold but this changes bold to light. Any way around?

@Darius Miliauskas 2015-12-08 19:42:49

Actually, it works, But should it be "Category" or "Extention"? The difference explained here: stackoverflow.com/questions/7136124/…

@Javier Amor Penas 2018-10-01 13:31:27

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

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

@Malfunction 2019-05-03 15:18:29

Beautiful, thanks a lot for sharing this!

@shesh nath 2019-06-13 11:00:21

crash as soon as i run this code

@Javier Amor Penas 2019-06-13 14:54:43

@sheshnath can you give us more crash info ?

@shesh nath 2019-06-14 09:44:27

sorry mistake was from my side, font was not listed in info.plist

@midhun p 2019-07-22 05:24:28

semibold is not working can you check this issue?

@Javier Amor Penas 2019-07-24 14:46:55

@midhunp Could you be more explicit so that it is not working for you?. It works well for me with bold typeface.

@Annu 2018-09-19 12:30:40

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>

@nahung89 2016-11-08 10:23:32

Swift 4.1

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 {

    @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 else { return }

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

@Kappe 2016-11-18 19:11:25

best answer!! automatically override the system font, brilliant

@Lee Probert 2016-11-21 18:51:00

This is great, but I am struggling to convert to Swift 2.3. In particular, this bit: let initCoderMethod = class_getInstanceMethod(self, Selector(init(coder:))) let myInitCoderMethod = class_getInstanceMethod(self, Selector(init(myCoder:)))

@Oliver Apel 2017-01-19 11:56:36

@LeeProbert did you solved this for Swift 2.3 ?

@Lee Probert 2017-01-19 12:25:54

No. Sorry. Am migrating over to 3 now anyway.

@MJQZ1347 2017-01-30 13:03:24

@Leparevilo did you solve it? :D

@Oliver Apel 2017-02-01 15:29:45

@LeeProbert: No. Made it manually on all controls... I'm migrating to Swift 3, too...

@Perwyl Liu 2017-02-09 05:53:04

@nahung89 any idea how to override the system style as well? for weight Medium/Thin/light etc

@nahung89 2017-02-09 06:13:05

@PerwylLiu i'm not sure but you can check in default if it returns value like CTFontXXXUsage. If it has then you could add it as a new case and implement you own customize.

@Perwyl Liu 2017-02-15 03:49:57

@nahung89 i did a print for fontAttribute, it's CTFontMediumUsage. Thanks :)

@Perwyl Liu 2017-02-24 03:52:13

@nahung89 do you have any idea on how to remove the warnings for let initCoderMethod = class_getInstanceMethod(self, Selector("initWithCoder:"))

@nahung89 2017-02-24 04:34:11

@PerwylLiu as I know there is no way so far. Hope other guys can solve this warning.

@Perwyl Liu 2017-02-24 06:42:38

@nahung89 thanks for the reply :)

@Knowledge 2017-11-07 19:23:15

If somebody has problems with the "NSCTFontUIUsageAttribute" line: if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String { did the trick for me.

@Perwyl Liu 2017-12-28 07:27:18

if let fontAttribute = fontDescriptor.fontAttributes[UIFontDescriptor.AttributeName‌​(rawValue: "NSCTFontUIUsageAttribute")] as? String {

@Jonathan Tuzman 2018-01-23 05:09:44

When I implement this, it's never getting through if let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor { (i.e., it always skips to the else clause). Also it makes me add @objc to all the myXXSystemFont methods and the convenience init.

@aviran 2018-08-07 12:10:20

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

@Henry H Miao 2018-11-21 01:35:45

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

@nahung89 2018-11-22 14:26:55

@HenryHMiao No it won't. I have some apps which are already available on Appstore, i.e iAntiTheft.

@Greg Hilston 2019-05-07 18:01:17

Its been a year since this answer has been posted. Does anyone have a more "native" Apple way to achieve this?

@midhun p 2019-07-22 05:09:24

How can I use "semibold" with your code?, I had tried something but not worked well. pls help me

@nahung89 2019-07-23 17:56:45

@midhunp you can use CTFontDemiUsage font attribute for checking semi-bold font. Also provide semi-bold-font name in AppFontName enumeration. It's pretty straight-forward dude :D

@Karthickkck 2018-01-30 12:03:17

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

@Sandy Chapman 2015-02-10 19:57:34

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

extension UILabel {

    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 {

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

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

@Mason G. Zhwiti 2015-04-26 15:26:01

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?

@Mason G. Zhwiti 2015-04-26 15:40:53

Sorry, I meant .Cancel labels would normally be bold, and Default would normally be regular weight.

@Sandy Chapman 2015-05-07 12:03:16

@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.

@Mason G. Zhwiti 2015-05-07 16:35:13

@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?

@Sandy Chapman 2015-05-07 17:03:08

@MasonG.Zhwiti I've not tested this. I haven't done any Swift programming in several months. I'd suggest setting a breakpoint in where the fonts are set / loaded and ensure that they're being set properly. Also, the font names don't necessarily match the file names of the fonts, so that's something to watch out for. I'd suggest using this to print out all the names of the fonts that are available within your app.

@Mason G. Zhwiti 2015-05-09 17:03:01

@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.

@Georg 2015-08-12 13:48:34

For checking between bold and medium use font.description and check if the word medium and bold are in there... if bold is in there, then it's bold... if only medium is in there, then it's medium The downside of this solution is that it only works on UILabels... not on UITextView, ect...

@Andy Mortimer 2015-11-21 08:34:30

This is brilliant! Not only does it solve the problem neatly and concisely, but it's explained a lot about UIAppearance too.

@Fábio Oliveira 2014-04-13 12:23:28

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

@Utku Yıldırım 2014-04-30 14:27:27

How you use this implementation on iOS6 which dont have UIFontDescriptor

@Fábio Oliveira 2014-05-05 13:12:29

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.

@Utku Yıldırım 2014-05-06 07:30:04

Thanks for answer i used another solution for now. I will check it when i need it again :)

@nahung89 2014-10-10 06:12:52

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)

@Randomblue 2015-04-16 05:13:20

For some reason, on iOS 8, modals (UIAlertController) don't change font.

@Ravi 2017-04-18 16:16:30

@Fábio Oliveira, your code is better, Apart from this please note that if there are multiple font types set in your project, and you want to SET ONLY ONE then change your this line code : else { fontName = descriptor.fontAttributes[@"NSFontNameAttribute"]; } to else { fontName [email protected]"yourFontName"; }

@Mubeen Qazi 2018-08-15 08:26:10

I have added following conditions and now this covers all the cases, might be helpful for someone. else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontDemiUsage"]) { fontName = FOSemiBoldFontName; } else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontMediumUsage"]) { fontName = FOSemiBoldFontName; } else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontHeavyUsage"]) { fontName = FOBoldFontName; }

@Randall 2012-01-03 05:10:51

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.

@Brandon 2012-01-26 19:10:12

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.

@Michael Forrest 2012-05-17 09:51:47

Can I do this without overriding the point size of every instance?

@jonsibley 2012-07-18 04:03:00

@Brandon you can specify the font without specifying the font size by setting the UIFont size to 0.0

@Ben Clayton 2012-10-10 11:22:39

@jonsibley. Are you sure about this? When I tried setting font size to 0.0 I get errors saying ' <Error>: CGAffineTransformInvert: singular matrix.' and the font doesn't appear at all. The docs say '[the size] must be greater than 0.0' See developer.apple.com/library/ios/#documentation/uikit/referen‌​ce/…

@Anand 2012-10-30 10:53:33

setFont: method is deprecated

@M. Ryan 2013-02-22 15:38:04

Is there any replacement for setFont now that it is deprecated?

@Adrian Schönig 2013-02-23 23:43:52

@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.

@Alastair Stuart 2013-03-20 01:05:03

@Anand it is not deprecated for UILabel.

@OMGPOP 2013-06-27 14:37:50

@AlastairStuart it's deprecated.

@Ben Flynn 2013-08-11 07:07:46

The docs are clear, the font property UILabel is not deprecated. If you are getting warnings it's because +appearance returns an id and XCode is probably looking up the wrong base class (UITableViewCell, for example). developer.apple.com/library/ios/documentation/uikit/referenc‌​e/…

@lppier 2013-08-15 01:58:26

@Michael Forrest Were you able to avoid override the point size of every instance eventually? I have the same porblem. Setting font size to 0.0 doesn't work for me as well.

@Fattie 2014-07-28 13:05:45

It really just does not work because of the size issue, unfortunately. (And after all, in some projects you want to be able to "set the size" in storyboard, and sometimes it's something else - maybe the colour.) I recommend just giving up and doing what I mention in the doing comment under the answer. It solves all problems.

@byJeevan 2014-12-21 06:46:26

Thanks a lot : -) Happy Coding ... :-))

@Sergey Skoblikov 2015-02-12 18:08:17

This method does not distinguish between different uses of UILabel's. For example in UITableView title and subtitle labels will use the same font and this is clearly not a way to customize you app. And appearanceWhenContainedIn: won't help either. There is no way to distinguish those to label that I'm aware of.

@Nik Kov 2016-06-24 08:13:39

To keep font, maybe this helps: [[UILabel appearance] setFont:[UIFont fontWithName:@"YourFontName" size:[UILabel appearance].font.pointSize]];

@Hugues BR 2013-07-31 17:46:25

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.

@Rambatino 2013-08-22 13:48:26

Is this within apple guidelines?

@Hugues BR 2013-08-22 17:28:03

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

@mxcl 2014-02-06 20:56:08

This is fine. Apple just don't want you using undocumented functions. You are allowed to “swizzle” methods that are public.

@Fábio Oliveira 2014-04-09 15:43:38

I have this implemented but it doesn't always work. For instance on UITableViewCell with default styles it doesn't apply my custom font. Actually I can see the method is called but the size I get is 0. Any ideas?

@GreatWiz 2014-05-14 15:06:28

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

@Fattie 2014-07-28 12:50:57

(1) this is 1000% ok from Apple's point of view (2) using a category on a default like this, usually sort of "causes an argument" amongst programmers. for example, the very best, perhaps only decent, way to "hide the status bar" in an app on iOS7 is like this .. stackoverflow.com/a/21034908/294884 ... but you always get some programmers who argue (quite rightly) that such categories are "undefined" in current compilers (although it works 100% perfectly) Hope it helps someone

@Mike Gledhill 2014-12-05 12:31:51

Brilliant ! An excellent way to change the Font on all controls, even Navigation Bar titles.

@Krutarth Patel 2015-05-09 07:43:56

my question is if i implement this ,font size will also over rided. how to avoid this ?

@rebellion 2015-06-15 13:58:35

Thanks for this solution, great!

@Nathan Hosselton 2015-07-31 17:46:34

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/…

@tanzolone 2017-05-31 10:15:44

"This will replace the default implementation and most UIControls use systemFont." is just plain wrong and I don't understand why it gets so many up-votes (the fact that this might work doesn't make it right). A category is not a subclass, you're not guaranteed that a duplicated implementation (as this shouldn't be called an override) will be used by the compiler - it is undefined whether the compiler will choose the original implementation or what you put in the category. If you really want to pursue this sort of approach you should looking into runtime swizzling, as already pointed it out.

@malhal 2017-09-20 02:04:49

I disagree with that link to a swizzling solution, it attempts to override the load method which has the exact same risk as this answer. Do the swizzling somewhere else, not in a category.

@Rmalmoe 2018-07-17 21:07:06

This is done in a one liner here (Swift 4)... stackoverflow.com/a/51390172/3900139

@A.G 2016-01-30 06:47:26

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

@Peng Xiaofeng 2015-11-26 09:25:02

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.

@Gingi 2014-06-25 19:15:06

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.

@Tom 2012-11-27 19:11:34

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.

@Daniel 2012-01-03 03:18:29

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

@Sam Jarman 2012-01-03 07:40:27

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

@Paulo Casaretto 2012-04-27 13:08:50

I disagree with what you did. The answer you selected is not valid when your question is tagged iphone-sdk-4.0.

@Sam Jarman 2013-01-02 11:56:10

corrected, my apologies. :)

@Bill 2013-12-04 15:08:59

@Sam Jarman, Randall's answer below is correct - can you mark it that way for future visitors?

Related Questions

Sponsored Content

31 Answered Questions

[SOLVED] Loaded nib but the 'view' outlet was not set

49 Answered Questions

[SOLVED] Vertically align text to top within a UILabel

7 Answered Questions

[SOLVED] How to add multiple font files for the same font?

18 Answered Questions

[SOLVED] How can I change font size in Eclipse for Java text editors?

43 Answered Questions

[SOLVED] iOS 8 UITableView separator inset 0 not working

42 Answered Questions

[SOLVED] Passing Data between View Controllers

32 Answered Questions

[SOLVED] Can I embed a custom font in an iPhone application?

  • 2008-12-11 20:21:11
  • Airsource Ltd
  • 235819 View
  • 771 Score
  • 32 Answer
  • Tags:   ios cocoa-touch fonts

17 Answered Questions

[SOLVED] How to Set a Custom Font in the ActionBar Title?

6 Answered Questions

[SOLVED] UIButton custom font vertical alignment

2 Answered Questions

[SOLVED] Setting Default fonts for whole app

  • 2014-01-20 09:22:01
  • Mario
  • 2444 View
  • 0 Score
  • 2 Answer
  • Tags:   android fonts

Sponsored Content