1

I have a UIButton with a variable titleLabel text. What I'm trying to accomplish (with AutoLayout) is that the button grows to fit the title, even when the title will need more then one line. So it has to grow in width first, and when the width reaches it's limit, it has to grow in height to fit the title. Like scenario C in the image below:

Autolayout challenge: growing UIButton

First of all: I accomplished my goal. Thanks to this and another post I subclassed UIButton and the button now works as I want it to. This is my UIButton code:

class JvBstretchableButton: UIButton {

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

        self.titleLabel?.numberOfLines = 0
        self.titleLabel?.lineBreakMode = .ByWordWrapping
    }

    override func intrinsicContentSize() -> CGSize {

        return (self.titleLabel?.intrinsicContentSize())!
    }

    override func layoutSubviews() {

        super.layoutSubviews()

          /*
    Set the preferredMaxLayoutWidth of the titleLabel to the width of the superview minus 
two times the known constant value for the leading and trailing button constraints 
(which is 10 each). I'm looking for another way to do this. I shouldn't have to hardcode 
this right? Autolayout knows the width of the surrounding view and all the relevant  constraint 
constants. So it should be able to figure out the preferredMaxLayoutWidth itself.
        */

        self.titleLabel?.preferredMaxLayoutWidth = superview!.frame.width - 20
        super.layoutSubviews()
    }
}

However, I have the strong feeling that I'm missing something and that there must be an easier way to do this. That brings me to my questions:

A) Is there really the need for a UIButton subclass, or is there an alternative, easier approach?

B) In case we can't prevent subclassing UIButton: isn't there a way to let AutoLayout figure out what will be the maximum width of the button? I now have to manually pass the frame of the superview and 'hardcode' the constants of the button constraints.

Community
  • 1
  • 1
Tuslareb
  • 1,200
  • 14
  • 21

1 Answers1

4

You could probably get that result using a (multi-line) UILabel and a UIButton and no subclassing. Configure your UILabel to be multiline (i.e. 0 lines) and align all the button edges to those of the UILabel. The UILabel will resize according to content and the button will follow. you can then use the UILabel as your button's text or just place it underneath the button and duplicate the button's text in it programatically.

Alain T.
  • 40,517
  • 4
  • 31
  • 51
  • Thank you! It's a bit of a hack, but your solution worked. Besides that, it's easier to get the content insets right. Put the label behind the button, connect the button to the label with constrains that are are equal to the wanted insets. Subsequently, add the same edge insets to the button itself and make sure that the button text and the 'label behind the button' text have the same font(size). Oh, and off course set the button title itself to multi line. – Tuslareb Jan 13 '16 at 08:13
  • Thanks for the insight. I'm curious as to why buttons don't grow with their title lines, but so be it. This got me on the right track. – Maxwell Feb 01 '17 at 04:17