0
votes

I have a button that repeats throughout my app, so I created a subclass to avoid having to set all the basic properties every time.

I am able to set the background colour, the text colour, round the corners.

However, things fall apart when I try to set a default title - something other than "Button". In Interface Builder it ignores the title, but it also then ignores the font colour, which works when I don't set the title.

If I run the app, it all looks fine, but one major point of using Interface Builder is to save the step of constantly running the app to check basic UI layout.

compare Interface Builder with Actual app

Here is the subclass. Note that if you comment out the 2 setTitle lines, the button shows the correct text colour (white).

import UIKit

@IBDesignable class ContinueButton: UIButton {

    @IBInspectable var titleColour: UIColor = .white {
        didSet {
            setTitleColor(titleColour, for: .normal)
        }
    }

    @IBInspectable var bgColour: UIColor = UIColor.gray {
        didSet {
            backgroundColor = bgColour
        }
    }

    @IBInspectable var buttonTitle: String = "Continue" {
        didSet {
            setTitle(buttonTitle, for: .normal)
        }
    }

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

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

    public func setAttributes() {
        setTitleColor(titleColour, for: .normal)
        backgroundColor = bgColour
        setTitle(buttonTitle, for: .normal)
    }

    override public func layoutSubviews() {
        super.layoutSubviews()

        setAttributes()

        layer.cornerRadius = 0.5 * bounds.size.height
        clipsToBounds = true
    }
}

ps, My main objective is to create a reusable custom button that takes care of setting a bunch of defaults. If there's a better way to achieve that, I'd be very happy to hear that - especially if it could be done visually rather than through code.

Thanks for any advice you can give,

-Nico

2
First, why are you renaming things? Use backgroundColor, etc. Don't reinvent the wheel! (You've already subclassed UIButton.) Second, have you set the IB (or storyboard) button to actually be a ContinueButton? Finally, if you need an example of what I'm saying, refer to my answer on this: stackoverflow.com/questions/42041809/… Basically, subclass, set IBDesignable/IBInspectable, and the expose - using the already established properties - what you need.dfd
I'm renaming because (according to the error messages) you cannot override a variable and then set an initial value to it. The example you show accesses the same named variables in Layer, not directly in UIButton.Nico teWinkel
And yes, I did set the button class - without it the end result would not look like my sample pictures. To clarify - I'm trying to use the subclass to avoid setting all the attributes in every button created in IB. The example I showed in the picture uses the attributes set by the subclass only - I didn't customize that button in IB.Nico teWinkel

2 Answers

0
votes

Just override prepareForInterfaceBuilder() and add setAttributes().

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    setAttributes()
}
0
votes

The tintColor property will do the trick. button.tintColor = UIColor.red

but to make sure to override the prepareForInterfaceBuilder()

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    button.tintColor = UIColor.red
}