Multiline UIButton and autolayout
I had the same problem where I wanted my button to grow along with its title. I had to sublcass the UIButton
and its intrinsicContentSize
so that it returns the intrinsic size of the label.
- (CGSize)intrinsicContentSize{ return self.titleLabel.intrinsicContentSize;}
Since the UILabel
is multiline, its intrinsicContentSize
is unknown and you have to set its preferredMaxLayoutWidth
See objc.io article about that
- (void)layoutSubviews{ [super layoutSubviews]; self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width; [super layoutSubviews];}
The rest of the layout should work. If you set your both button having equal heights, the other one will grow to. The complete button looks like this
@implementation TAButton- (instancetype)initWithCoder:(NSCoder *)coder{ self = [super initWithCoder:coder]; if (self) { self.titleLabel.numberOfLines = 0; self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; } return self;}- (CGSize)intrinsicContentSize{ return self.titleLabel.intrinsicContentSize;}- (void)layoutSubviews{ [super layoutSubviews]; self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width; [super layoutSubviews];}@end
Swift 4.1.2 Version based on @Jan answer.
import UIKitclass 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 { get { return titleLabel?.intrinsicContentSize ?? CGSize.zero } } override func layoutSubviews() { super.layoutSubviews() titleLabel?.preferredMaxLayoutWidth = titleLabel?.frame.size.width ?? 0 super.layoutSubviews() }}
This respects content edge insets and worked for me:
class MultilineButton: UIButton { func setup() { self.titleLabel?.numberOfLines = 0 self.setContentHuggingPriority(UILayoutPriorityDefaultLow + 1, for: .vertical) self.setContentHuggingPriority(UILayoutPriorityDefaultLow + 1, for: .horizontal) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } override init(frame: CGRect) { super.init(frame: frame) setup() } override var intrinsicContentSize: CGSize { let size = self.titleLabel!.intrinsicContentSize return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom) } override func layoutSubviews() { super.layoutSubviews() titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width }}