3

I tried to set the font of UIButton via appearance proxy. But it doesn't seem to work. This is what I tried.

UIButton.appearance().titleFont = UIFont(name: FONT_NAME_DEFAULT, size:20.0) UIButton.appearance().titleLabel?.font = UIFont(name: FONT_NAME_DEFAULT, size:20.0)

How to set UIButton font via appearance proxy in iOS 8 ?

EDIT: Found in vaberer's link: "I'm surprised that UIButton doesn't have any UI_APPEARANCE_SELECTOR properties, yet conforms to the UIAppearance protocol."

Community
  • 1
  • 1
Hlung
  • 13,850
  • 6
  • 71
  • 90
  • 1
    As of iOS 9 you can use `UILabel.appearance(whenContainedInInstancesOf: [UIButton.self]).font = ...` – Kevin Jun 07 '17 at 21:22

5 Answers5

12

Had the same problem with a theme-able app.

1. Add this extension

// UIButton+TitleLabelFont.swift

import UIKit

extension UIButton {
    var titleLabelFont: UIFont! {
        get { return self.titleLabel?.font }
        set { self.titleLabel?.font = newValue }
    }
}

2. Then setup the UIButton appearance prototype object

class Theme {
    static func apply() {
       applyToUIButton()
       // ...
    }

    // It can either theme a specific UIButton instance, or defaults to the appearance proxy (prototype object) by default
    static func applyToUIButton(a: UIButton = UIButton.appearance()) {
       a.titleLabelFont = UIFont(name: FONT_NAME_DEFAULT, size:20.0)
       // other UIButton customizations
    }
}

3. Drop the theme setup in app delegate

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    Theme.apply()

    // ...

    return true
}

If you're preloading stuff (lazy var VCs from storyboards) earlier, it may be better to instead of using app delegate setup the theme stuff in an override initializer like so:

private var _NSObject__Theme_apply_token: dispatch_once_t = 0

extension NSObject {
    override public class func initialize() {
        super.initialize()
        // see also: https://stackoverflow.com/questions/19176219/why-am-i-getting-deadlock-with-dispatch-once
        var shouldRun = false
        dispatch_once(&_NSObject__Theme_apply_token) {
            shouldRun = true
        }
        if shouldRun {
            Theme.apply()
        }
    }
}
  • 1
    Step 1 is a great idea, and was all I needed to then use the appearance API in the standard way. – Luke Rogers Jun 13 '16 at 18:52
  • Not sure this works anymore as it looks like Apple removed the font from the appearance API for UILabel. Also, I believe you could've just used the 'contained in' version for the label within a UIButton rather than having to use the extension, but again, that won't work now either. – Mark A. Donohoe Oct 06 '18 at 06:40
3

Barry's answer works great but the UIButton extension implementation is out of date - you need declare var titleLabelFont like:

@objc dynamic var titleLabelFont: UIFont! {
    get { return self.titleLabel?.font }
    set { self.titleLabel?.font = newValue }
  }

See full implementation here: http://blog.iseinc.biz/use-uiappearance-create-ios-app-themes

Ricky Padilla
  • 226
  • 5
  • 7
  • I tried Barry's solution (without the `NSObject` extension), and it did not work. Adding `@objc dynamic` was the key to making it work. – kwahn Jan 31 '19 at 16:23
1

Set the UIButton's font with UIAppearance as follows:

label = UILabel.appearance(whenContainedInInstancesOf: [UIButton.self])
label.font = UIFont.systemFont(ofSize: 20)

You may add the above code in your AppDelegate's method application(_:, didFinishLaunchingWithOptions:), or wherever it is appropriate to set the theme for your application.

In UIViewController.viewDidLoad set adjustsFontForContentSizeCategory property of the button instance's titleLabel to true.

class ExampleVC: UIViewController

    @IBOutlet weak var btnOkay: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        btnOkay.titleLabel?.adjustsFontForContentSizeCategory = true
    }
}
Litehouse
  • 864
  • 8
  • 14
-1

You are trying to set a font of UILabel inside UIButton. Since UILabel is not tagged with UI_APPEARANCE_SELECTOR. You can't do it like this.

Look at the list of the UIAppearance elements at: What properties can I set via an UIAppearance proxy?

Community
  • 1
  • 1
Patrik Vaberer
  • 646
  • 6
  • 15
  • 1
    Found in your link: "I'm surprised that UIButton doesn't have any UI_APPEARANCE_SELECTOR properties, yet conforms to the UIAppearance protocol. Is this an oversight by Apple?" – Hlung Apr 25 '15 at 11:20
  • Yes, but since titleLabel property return optional UILabel, you need to look at UILabel's appearance. – Patrik Vaberer Apr 25 '15 at 11:44
-1

You can apply it to the label when contained in a button:

UILabel.appearance(whenContainedInInstancesOf: [UIButton.self])
  .font = .systemFont(ofSize: 19, weight: .medium)
TruMan1
  • 33,665
  • 59
  • 184
  • 335
  • 1
    This might sound weird, but set the font size to 17 in storyboard and it should kick in. Seems to be a magic default number or bug. – TruMan1 Mar 30 '19 at 21:22