Custom UIButton class does not show title - ios

I have created a custom UIButton class. But the title does not show up. I only get the background color and the rounded corners. But the title is not visible.
Also when I run it in simulator, iOS 13+, its showing the title white. But when I run in my device i.e. iOS 12.4, its not working.
Here is my code:
public class CornerButton : UIButton {
public override init(frame: CGRect) {
super.init(frame: frame)
setup()
self.layoutIfNeeded()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
self.layoutIfNeeded()
}
func setup() {
self.titleLabel?.font = UIFont(name: "Poppins-SemiBold", size: 12)
self.backgroundColor = UIColor(named: "BarColor")
self.setTitleColor(.white, for: .normal) // this line is not working
self.clipsToBounds = true
}
public override func layoutSubviews() {
self.roundCorners(corners: [.topRight,.bottomLeft], radius: 10)
}
}

You need to call super.layoutSubviews()
public override func layoutSubviews() {
super.layoutSubviews()
self.roundCorners(corners: [.topRight,.bottomLeft], radius: 10)
}
BTW here you don't need layoutSubviews as you use it when you need to make something that depends on the actual measured bounds of the view and as you set a static radius you can omit it

Related

UIButton TitleLabel - How to set UIButton's font when titleLabel is nil?

I am trying change the font of a button class (before the button is initiated), but it does not work. It seems that the "titleLabel" is the issue since it is nil.
guard let object = NSClassFromString(button.key) as? UIButton.Type else { return }
let buttonClass = object.self
buttonClass.appearance().titleLabel?.text = UIFont(name: "HelveticaNeue-Thin", size: 20)
Here the titleLabel is nil, so it won't work.
I have also tried setting the label's font in my class (MBButton is my class), but this does not work as well
UILabel.appearance(whenContainedInInstancesOf[MBButton.self]).font = UIFont(name: "HelveticaNeue-Thin", size: 20)
You can set the title label's font in your subclassed buttons setup:
#IBDesignable
class MMButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
commonInit()
}
func commonInit() -> Void {
titleLabel?.font = UIFont(name: "HelveticaNeue-Thin", size: 20)
// other customization here...
}
}
Alternatively, if you want to use the .appearance() method, add an extension:
class MMButton: UIButton {
// whatever you're doing for customization
}
extension MMButton {
#objc dynamic var titleLabelFont: UIFont! {
get { return self.titleLabel?.font }
set { self.titleLabel?.font = newValue }
}
}
then,
MMButton.appearance().titleLabelFont = UIFont(name: "HelveticaNeue-Thin", size: 20)
The best would be doing was #DonMag said. If you insist on using appearance, then you need to set titleFont on buttonClass.appearance() instead of titleLabel?.text

IBDesignable class don't seems to work properly

I'm building a new iOS app with swift and trying to make a custom IBDesignable UIButton class to use in the designer.
My code does not seems to work either in the builder or the app itself at runtime.
The default value i gave to the IBInspectable vars does not apply to them.
#IBDesignable class MyButton: UIButton {
#IBInspectable var backColor: UIColor = UIColor.red {
didSet {
self.backgroundColor = backColor
}
}
#IBInspectable var textColor: UIColor = UIColor.white {
didSet {
self.setTitleColor(textColor, for: .normal)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
private func setup() {
titleLabel?.font = UIFont.systemFont(ofSize: 17)
contentEdgeInsets = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
layer.cornerRadius = (frame.height / 2)
setTitle(title(for: .normal)?.uppercased(), for: .normal)
}
}
I expect to see the button in the designer/app with a red background and a white text and none of these happens.
I'm using Swift 4.2 and Xcode 10.1.
add this two func s
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.setup()
}
no need for init
Setting a property default value does not invoke the didSet clause.
You need something like:
private func setup() {
titleLabel?.font = UIFont.systemFont(ofSize: 17)
contentEdgeInsets = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
layer.cornerRadius = (frame.height / 2)
setTitle(title(for: .normal)?.uppercased(), for: .normal)
// I would do it differently, but this is just for demo purposes
// Also, can't assign a prop to itself, so using a temp
var tmp = self.backColor
self.backColor = tmp
tmp = self.textColor
self.textColor = tmp
}
Additionally, Xcode is not very good with IBDesignable, in swift or objective C.
Make sure the menu item: Editor -> Automatically Refresh Views is checked.
You can also explicitly do Editor -> Refresh All Views.
From my experience - this stops working after a while, and you need to quit Xcode and restart it to make it work again.
Make sure that your button is set to type .custom in your Interface Builder.
This is not obvious but the default button type is .system, which cannot be customized. I saw people having no problems with this but in my applications this was always a problem.
Another problem is that if you keep your inspectable values empty, the didSet won't be called and the default value won't be applied.
#IBInspectable var backColor: UIColor? = UIColor.red {
didSet {
updateBackground()
}
}
private func updateBackground() {
self.backgroundColor = backColor
}
func setup() {
...
updateBackground()
}

Xcode #IBDesignable Button Background Color Not Rendering In Storyboard

Trying to show the button background color in the storyboard, the following code renders the border width and radius correctly but background doesn't show. In the simulator, the button's background color is rendered correctly.
import UIKit
let colorSunset = #colorLiteral(red: 0.9693382382, green: 0.5568749309, blue: 0, alpha: 1)
#IBDesignable class PrimaryButtonA: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
buttonA()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
buttonA()
}
func buttonA() {
self.layer.cornerRadius = 10
self.layer.borderWidth = 5
self.layer.backgroundColor = colorSunset.cgColor
}
}
Code Screenshot
Storyboard Screenshot
Simulator Screenshot
Xcode doesn't show any errors but there is a warning which is unrelated and is about the button's fixed width and height and the text will be clipped.
Thanks in advance for the help.
This is the solution that worked for me.
import UIKit
let colorSunset = #colorLiteral(red: 0.9693382382, green: 0.5568749309, blue: 0, alpha: 1)
#IBDesignable class PrimaryButtonA: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
buttonA()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
buttonA()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
backgroundColor = colorSunset
}
func buttonA() {
self.layer.cornerRadius = 10
self.layer.borderWidth = 5
// self.layer.backgroundColor = colorSunset.cgColor
}
}
There is no solution to this. This problem occurs because some times storyboard does not recognize IBDesignables. When you restart your XCode sometimes it gets recognized and sometimes it doesn't.

Rounded UIButton - iPad size

I have custom UIButton to have rounded edges
import UIKit
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = self.bounds.width * 0.5
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.cornerRadius = self.bounds.width * 0.5
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
}
Now I am using this "RoundedButton" (size of 110, 110) in a UIViewcontroller's XIB file and the constraints are set to maintain the aspect ratio w.r.t UIViewcontrollers view.
The button looks rounded in iPhone simulators but the button is NOT rounded in iPad simulator. When I set the layer.cornerRadius property in viewDidAppear then the button is rounded in iPad simulator.
Please see images
I am looking for an alternative solution than re-defining layer corner radius again in viewDidappear.
Thanks
override method layoutSubviews like this:
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width * 0.5
}
Also you can now remove cornerRadius line from init
For more go to documentation of UIView: https://developer.apple.com/documentation/uikit/uiview/1622482-layoutsubviews
Override layoutSubviews function:
import UIKit
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width * 0.5
}
}
import UIKit
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width / 2
}
}
I have also create a code sample for you. RoundedButton

Title not showing for custom UIButton class

I have created a custom UIButton class which features a round frame. The problem is although I set up the title property of each button from the storyboard they are not showing. I end up with round buttons with no titles showing inside them. I am trying to do a keypad like the one in default iOS passcode screen. My main view background color is not white and I am not using any background images for the buttons. Here is my code for the custom UIButton class.
import Foundation
import UIKit
class MyOwnButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
self.clipsToBounds = true
self.titleLabel?.font = UIFont.systemFontOfSize(33.0)
self.titleLabel?.textColor = UIColor.whiteColor()
self.layer.cornerRadius = self.frame.size.width / 2.0
self.layer.borderColor = UIColor.whiteColor().CGColor
self.layer.borderWidth = 2.0
}
}
Had same issue, this answer worked for me: Custom UIButton subclass not displaying title
Add super.layoutSubviews() after you override the function.
Have you set your UIButton's class as your custom class in storyboard??
Try to put all the things in init method and check.
import Foundation
import UIKit
class MyOwnButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
self.clipsToBounds = true
self.titleLabel?.font = UIFont.systemFontOfSize(33.0)
self.titleLabel?.textColor = UIColor.whiteColor()
self.layer.cornerRadius = self.frame.size.width / 2.0
self.layer.borderColor = UIColor.whiteColor().CGColor
self.layer.borderWidth = 2.0
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Here is working code for Swift 4
import UIKit
class MyOwnButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
commonSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonSetup()
}
private func commonSetup() {
self.clipsToBounds = true
self.titleLabel?.font = UIFont.systemFont(ofSize: 33.0)
self.titleLabel?.textColor = UIColor.white
self.layer.cornerRadius = self.frame.size.width / 2.0
self.layer.borderColor = UIColor.white.cgColor
self.layer.borderWidth = 2.0
}
}
After setting the title of the button, simply:
[button sizeToFit];

Resources