Skip to content

Instantly share code, notes, and snippets.

@brynbodayle
Created July 25, 2014 16:29
Show Gist options
  • Save brynbodayle/de70eb6a392e90272707 to your computer and use it in GitHub Desktop.
Save brynbodayle/de70eb6a392e90272707 to your computer and use it in GitHub Desktop.
Multiline UIButton + Auto Layout
- (CGSize)intrinsicContentSize {
CGSize boundingSize = CGSizeMake(self.titleLabel.preferredMaxLayoutWidth - self.titleEdgeInsets.left - self.titleEdgeInsets.right, CGFLOAT_MAX);
NSAttributedString *attributedTitle = [self attributedTitleForState:self.state];
CGRect boundingRect;
if(attributedTitle) {
boundingRect = [attributedTitle boundingRectWithSize:boundingSize options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) context:NULL];
}
else {
NSString *title = [self titleForState:self.state];
boundingRect = [title boundingRectWithSize:boundingSize options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName : self.titleLabel.font} context:NULL];
}
return CGSizeMake(boundingRect.size.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right, boundingRect.size.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}
@brynbodayle
Copy link
Author

Here's a little code snippet for a UIButton subclass which allows you to use a multi line UIButton with Auto Layout. This also solves the issue UIButton can have with Auto Layout where it doesn't allot for the titleEdgeInsets.

Just make sure you are setting the preferredMaxLayoutWidth for your label so it will wrap correctly. Here's a great post describing how to do that.
http://devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html

Unfortunately this only seems to be working in iOS 8 right now.

@AlexandrGraschenkov
Copy link

This do not work for me. In result I get this solution:

override func intrinsicContentSize() -> CGSize {
    let size = titleLabel?.intrinsicContentSize() ?? CGSizeZero
    return CGSizeMake(size.width + titleEdgeInsets.left + titleEdgeInsets.right, size.height + titleEdgeInsets.top + titleEdgeInsets.bottom)
}

@seapy
Copy link

seapy commented Feb 25, 2016

@AlexandrGraschenkov solution is works

@mickeyl
Copy link

mickeyl commented Mar 14, 2017

Works fine, however I found that we need to take contentEdgeInsets into account as well, since some people might have set both.

@starduliang
Copy link

@lalkrishna
Copy link

This works for me.

class MultiLineButton: UIButton {

    // MARK: - Init

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

        self.commonInit()
    }

    private func commonInit() {
        self.titleLabel?.numberOfLines = 0
        self.titleLabel?.lineBreakMode = .byWordWrapping
    }

    // MARK: - Overrides

    override var intrinsicContentSize: CGSize {
        titleLabel?.intrinsicContentSize ?? .zero
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        titleLabel?.preferredMaxLayoutWidth = titleLabel?.frame.size.width ?? 0
        super.layoutSubviews()
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment