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

5

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

Vesting answered 25/4, 2015 at 7:8 Comment(1)
As of iOS 9 you can use UILabel.appearance(whenContainedInInstancesOf: [UIButton.self]).font = ...Ceiba
E
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://mcmap.net/q/911051/-why-am-i-getting-deadlock-with-dispatch_once
        var shouldRun = false
        dispatch_once(&_NSObject__Theme_apply_token) {
            shouldRun = true
        }
        if shouldRun {
            Theme.apply()
        }
    }
}
Entomostracan answered 3/6, 2015 at 7:19 Comment(2)
Step 1 is a great idea, and was all I needed to then use the appearance API in the standard way.Thekla
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.Ogden
Q
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

Quay answered 1/11, 2018 at 16:47 Comment(1)
I tried Barry's solution (without the NSObject extension), and it did not work. Adding @objc dynamic was the key to making it work.Simdars
D
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
    }
}
Daub answered 29/3, 2021 at 11:25 Comment(0)
R
-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?

Ruelle answered 25/4, 2015 at 8:6 Comment(2)
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?"Vesting
Yes, but since titleLabel property return optional UILabel, you need to look at UILabel's appearance.Ruelle
S
-1

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

UILabel.appearance(whenContainedInInstancesOf: [UIButton.self])
  .font = .systemFont(ofSize: 19, weight: .medium)
Saintsimonianism answered 23/10, 2018 at 13:47 Comment(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.Saintsimonianism

© 2022 - 2024 — McMap. All rights reserved.