29

I know that to set a custom font of an element on the screen I can simply dosomeLabel.font=UIFont(name: "Exo 2.0", size: 15).

I was wondering how one could set it for an entire app using swift. (A hack would be to do what I know for every single element of the app but that is just going to be a maintainability nightmare)

I see that this question has already been asked with an objective-C tag, How to set a custom font for entire iOS app without specifying size but I'm not familiar enough with objective-C enough to port the code to swift

1
  • You could write a UILabel extension that returns the font you want in place of its internal font property. Commented Jan 27, 2015 at 21:38

5 Answers 5

37

You can set the appearance of the UILabel and other UIViews:

UILabel.appearance().font = UIFont(name: "yourFont", size: yourSize)

More General:

AnyUIView.appearance().font = UIFont(name: "yourFont", size: yourSize)
Sign up to request clarification or add additional context in comments.

4 Comments

my question is if i implement this,font size will also will over rided? how to avoid this ?
this works great for not overriding font sizes!
Is there a way to set the font globally like this without specifying the size? So that if I have a table cell with Subtitle style, the text will still show at the default size for those styles, in my chosen font?
@KrutarthPatel See my solution below. Font size is not overridden.
24

As a more detailed answer and with these benefits I recommend using extensions:

  • No size override (whatever you set in designer will be used)
  • No style override (Bold, Light, Medium, UltraLight is implemented in my code but you can customize it as you need)
import UIKit

extension UILabel {
    @objc var substituteFontName : String {
        get {
            return self.font.fontName;
        }
        set {
            let fontNameToTest = self.font.fontName.lowercased();
            var fontName = newValue;
            if fontNameToTest.range(of: "bold") != nil {
                fontName += "-Bold";
            } else if fontNameToTest.range(of: "medium") != nil {
                fontName += "-Medium";
            } else if fontNameToTest.range(of: "light") != nil {
                fontName += "-Light";
            } else if fontNameToTest.range(of: "ultralight") != nil {
                fontName += "-UltraLight";
            }
            self.font = UIFont(name: fontName, size: self.font.pointSize)
        }
    }
}

extension UITextView {
    @objc var substituteFontName : String {
        get {
            return self.font?.fontName ?? "";
        }
        set {
            let fontNameToTest = self.font?.fontName.lowercased() ?? "";
            var fontName = newValue;
            if fontNameToTest.range(of: "bold") != nil {
                fontName += "-Bold";
            } else if fontNameToTest.range(of: "medium") != nil {
                fontName += "-Medium";
            } else if fontNameToTest.range(of: "light") != nil {
                fontName += "-Light";
            } else if fontNameToTest.range(of: "ultralight") != nil {
                fontName += "-UltraLight";
            }
            self.font = UIFont(name: fontName, size: self.font?.pointSize ?? 17)
        }
    }
}

extension UITextField {
    @objc var substituteFontName : String {
        get {
            return self.font?.fontName ?? "";
        }
        set {
            let fontNameToTest = self.font?.fontName.lowercased() ?? "";
            var fontName = newValue;
            if fontNameToTest.range(of: "bold") != nil {
                fontName += "-Bold";
            } else if fontNameToTest.range(of: "medium") != nil {
                fontName += "-Medium";
            } else if fontNameToTest.range(of: "light") != nil {
                fontName += "-Light";
            } else if fontNameToTest.range(of: "ultralight") != nil {
                fontName += "-UltraLight";
            }
            self.font = UIFont(name: fontName, size: self.font?.pointSize ?? 17)
        }
    }
}

Samples for using Extensions:

e.g. put these lines in your starting controller viewDidLoad

UILabel.appearance().substituteFontName = "IRANSans"; // USE YOUR FONT NAME INSTEAD
UITextView.appearance().substituteFontName = "IRANSans"; // USE YOUR FONT NAME INSTEAD
UITextField.appearance().substituteFontName = "IRANSans"; // USE YOUR FONT NAME INSTEAD

P.S. as @Christian mentioned, you can write your own extensions for almost AnyUIView

6 Comments

Is this still working for iOS 11 and swift 4? I got nil for the self.font.fontName in UILabel
I will check and let you know the result soon
Update: you have to add @objc to substituteFontName for keep the compatibility with swift4
Need to add @objc in order to work in swift project.
how to replace attributed text font globally using same concept ?
|
5

FINALLY figured this out. Cleanest way I could find. (Swift 4) Solution doesn't require you to set font sizes and won't override all font sizes.

  UILabel.appearance().font = UIFont.preferredFont(forTextStyle: UIFontTextStyle(rawValue: "Roboto"))

For those looking for where to place this code. I put it in my AppDelegate.swift file inside of

 func application(_ application: UIApplication, 
 didFinishLaunchingWithOptions...

Swift 4.2

 UILabel.appearance().font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle(rawValue: "Roboto"))

5 Comments

@DanielBeltrami You can put this right in your app delegate inside of.... func application(_ application: UIApplication, didFinishLaunchingWithOptions And it should work application wide
Doesn't seems to work on iOS 12 with Swift 4.2, most of the texts' font size turn smaller then they should be.
At didFinishLaunchingWithOptions of course. But never mind, I found much better solution to change the font all over my app: stackoverflow.com/a/40484460/8157190
doesn't work. overrides all font sizes on labels. in swift 5.
The answer clearly states swift 4.2. So doesn't work, isn't actually a correct response if you aren't talking about the same version @spnkr
2

I found out a way to do same in Swift 4 with iOS 11

Only need to add @objc keyword before variable name. So variable declaration will be like this

@objc public var substituteFontName : String {
    get {}
    set {}
}

Hope this helps others who are facing this issue.

1 Comment

I was facing this issue and wasted more than 2 days of my time to figure it out! Thanks
0

The answer is a combination of the answers offered already, but I had to try a combination of things to get it working in iOS 13:

This is all placed in a Table View Controller, which is made to conform to the UIFontPickerViewControllerDelegate in order to offer a view for the user to pick the font. This will update all the UILabels with the new font, but keep the other attributes.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)

    if cell === fontCell {
        if #available(iOS 13, *) {
            let configuration = UIFontPickerViewController.Configuration()
            configuration.includeFaces = true

            let fontVC = UIFontPickerViewController(configuration: configuration)
            fontVC.delegate = self

            present(fontVC, animated: true)
        } else {
            let ac = UIAlertController(title: "iOS 13 is required", message: "Custom fonts are only supported by devices running iOS 13 or above.", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "OK", style: .default))
            present(ac, animated: true)
        }
    }
}

}

@available(iOS 13.0, *)
extension AppearanceTableViewController: UIFontPickerViewControllerDelegate {
    func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) {
        // attempt to read the selected font descriptor, but exit quietly if that fails
        guard let descriptor = viewController.selectedFontDescriptor else { return }

        let font = UIFont(descriptor: descriptor, size: 20)
        UILabel.appearance().substituteFontName = font.fontName
    }
}

extension UILabel {
    @objc public var substituteFontName : String {
        get {
            return self.font.fontName;
        }
        set {
            let fontNameToTest = self.font.fontName.lowercased()
            var fontName = newValue
            if fontNameToTest.range(of: "bold") != nil {
                fontName += "-Bold"
            } else if fontNameToTest.range(of: "medium") != nil {
                fontName += "-Medium"
            } else if fontNameToTest.range(of: "light") != nil {
                fontName += "-Light"
            } else if fontNameToTest.range(of: "ultralight") != nil {
                fontName += "-UltraLight"
            }
            self.font = UIFont(name: fontName, size: self.font.pointSize)
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.