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

Community
  • 1
  • 1
tawheed
  • 5,565
  • 9
  • 36
  • 63

5 Answers5

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)
Christian
  • 22,585
  • 9
  • 80
  • 106
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

Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
Mostafa Aghajani
  • 1,844
  • 2
  • 14
  • 19
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"))
Skai
  • 31
  • 1
  • 10
Rmalmoe
  • 993
  • 11
  • 13
  • 1
    @DanielBeltrami You can put this right in your app delegate inside of.... func application(_ application: UIApplication, didFinishLaunchingWithOptions And it should work application wide – Rmalmoe Sep 20 '18 at 15:39
  • 4
    Doesn't seems to work on iOS 12 with Swift 4.2, most of the texts' font size turn smaller then they should be. – Ido Nov 04 '18 at 17:02
  • At `didFinishLaunchingWithOptions` of course. But never mind, I found much better solution to change the font all over my app: https://stackoverflow.com/a/40484460/8157190 – Ido Nov 06 '18 at 11:19
  • 1
    doesn't work. overrides all font sizes on labels. in swift 5. – spnkr Sep 04 '19 at 15:59
  • 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 – Rmalmoe Sep 11 '19 at 14:21
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.

Surjeet Singh
  • 11,691
  • 2
  • 37
  • 54
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)
        }
    }
}
MihaiL
  • 1,558
  • 1
  • 9
  • 11