Reputation: 12332
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
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 ...
Upvotes: 0
Views: 711
Reputation: 14417
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)
}
}
}
Upvotes: 1
Reputation: 12332
I've tidied up Jawad's excellent information:
Firstly, at bringup time, you have to create the attributed title:
import UIKit
class SmallChatButton: UIIButton { // (note the extra "I" !!)
override func common() {
super.common()
backgroundColor = .your corporate color
contentEdgeInsets = UIEdgeInsets(top: 7, left: 11, bottom: 7, right: 11)
titles()
}
private func titles() {
let states: [UIControl.State] = [.normal, .highlighted, .selected, .disabled]
for state in states {
let currentText = super.title(for: state)
setTitle(currentText, for: state)
}
}
so to achieve that ..
override func setTitle(_ title: String?, for state: UIControl.State) {
let _f = UIFont.systemFont(ofSize: 10, weight: .heavy)
let attributedTitle = NSAttributedString(
string: title ?? "Click",
attributes: [
NSAttributedString.Key.kern: -0.5,
NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: _f
])
setAttributedTitle(attributedTitle, for: state)
}
override func layoutSubviews() { // example of rounded corners
super.layoutSubviews()
layer.cornerRadius = bounds.height / 2.0
clipsToBounds = true
}
}
Note that a kern of "-0.5" is about what most typographers want for typical "slightly tight type".
It looks good with say all caps, or a slightly bold font, or small type. The Apple measurement system is unlike anything used by typographers, so, you'll just have to vary it until the typographer on your app is satisfied.
What is UIIButton
(note the extra "I" !!)
Inevitably in any project you will need a UIButton which has an "I" initializer, so you'll proabbly have:
import UIKit
class UIIButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
common()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
common()
}
func common() {
}
}
(It's quite amazing that in iOS one has to do all of the above to "kern the system font" !)
Upvotes: 0