RobertoCuba
RobertoCuba

Reputation: 901

Best place to set cornerRadius based on UIButton size in subclass?

So I will be having a few different rounded buttons within an app (all the way to circular buttons), and from what I can tell, the easiest way to achieve this is to set the cornerRadius property of the buttons CALayer.

However, I don't want to be doing this manually for every button that requires it in every controller, so I thought a simple subclass that sets this on init would be the way.

I am using Storyboard and Autolayout to position and size the buttons, and assigning them to this subclass.

class RoundedButton: UIButton {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.layer.cornerRadius = self.bounds.size.height / 2.0
        self.clipsToBounds = true
        NSLog("BUTTON BOUNDS: H-%f  W-%f", self.bounds.size.height, self.bounds.size.width)
        NSLog("BUTTON FRAME: H-%f  W-%f", self.frame.height, self.frame.width)
    }
}

But I have come to find out that at this point (i.e. init), the size of neither the frame nor bounds are final. For a button in Storyboard sized (and constrained) to H40 x W40, the bounds/frame sizes are showing H30 x W38.

This means that cornerRadius doesn't get the value I expect.

I have confirmed that at some later point (e.g. when the button can already respond to a tap) that its frame/bounds are indeed H40 x W40.

So after all that, my question is, within the UIButton subclass, when/where can I safely set cornerRadius using the final frame/bounds values of the instance?

Upvotes: 8

Views: 2927

Answers (3)

Orn Arnarson
Orn Arnarson

Reputation: 136

Since you wish to use initWithCoder rather than initWithFrame (where you do have the frame struct), you can override the layoutSubviews method. When layoutSubviews is called the frame is correct.

In objective-c you can write

- (void)layoutSubviews {
    [super layoutSubviews];
    self.layer.cornerRadius = self.bounds.size.height/2;

}

Upvotes: 1

tom.e.kid
tom.e.kid

Reputation: 121

Try this in Button class.

override func layoutSubviews() {
    super.layoutSubviews()

    // here...
}

Upvotes: 1

Fantattitude
Fantattitude

Reputation: 1842

If you want your code to be executed after the view has gone through AutoLayout you must do it in layoutSubviews after calling super.layoutSubviews().

Like this :

class RoundedButton: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        layer.cornerRadius = bounds.size.height / 2.0
        clipsToBounds = true
    }
}

This code is not perfect though because it doesn't support when height is bigger than width (easy to fix though…).

Upvotes: 21

Related Questions