Search code examples
iosswiftuibuttonnsattributedstring

Subclass UIButton with system font, bold, and kerning


You have to use attributed text to do kerning. But. On the other hand, you can't get at system fonts in the IB attributed text menu.

How do I make (in code) a UIButton which has

  • system font, weight bold
  • size 11
  • kern attribute set to -2

Ideally it would collect the text of the button from plain text Title in IB. But if the text has to be set in code that is fine.

class NiftyButton: UIButton { 
    ????
}

Normally I initialize UIButton like this .. but I don't even know if that's the best place to do this? (You can't do it in layoutSubviews, since it will loop of course.)

class InitializeyButton: UIButton {

    override init(frame: CGRect) {
        super.init(frame: frame)
        common()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        common()
    }

    func common() {
        ...
    }
}

How to achieve in code ...

  • system font, weight bold
  • size 11
  • kern attribute set to -2

Solution

  • Here is the class you can use to get the desired result:

    class InitializeyButton: UIButton {
    
       @IBInspectable var spacing:CGFloat = 0 {
          didSet {
            updateTitleOfLabel()
          }
       }
    
       override func setTitle(_ title: String?, for state: UIControl.State) {
    
            let color = super.titleColor(for: state) ?? UIColor.black
            let attributedTitle = NSAttributedString(
                string: title ?? "",
                attributes: [NSAttributedString.Key.kern: spacing,
                             NSAttributedString.Key.foregroundColor: color,
                             NSAttributedString.Key.font: UIFont.systemFont(ofSize: self.titleLabel?.font.pointSize ?? 11, weight: .bold)   ])
            super.setAttributedTitle(attributedTitle, for: state)
       }
    
      private func updateTitleOfLabel() {
        let states:[UIControl.State] = [.normal, .highlighted, .selected, .disabled]
          for state in states {
            let currentText = super.title(for: state)
            self.setTitle(currentText, for: state)
          }
       }
    }