I have created a view controller that looks like this:
I want the two
A simple solution working for me: make the multiline button to respect its title height in Swift 4.2 by adding a constraint for the button's height based on its title label's height:
let height = NSLayoutConstraint(item: multilineButton,
attribute: .height,
relatedBy: .equal,
toItem: multilineButton.titleLabel,
attribute: .height,
multiplier: 1,
constant: 0)
multilineButton.addConstraint(height)
@Jan's answer doesn't work for me in (at least) iOS 8.1, 9.0 with Xcode 9.1. The problem: titleLabel
's -intrinsicContentSize
returns very big width and small height as there is no width limit at all (titleLabel.frame
on call has zero size that leads to measurements problem). Moreover, it doesn't take into account possible insets and/or image.
So, here is my implementation that should fix all the stuff (only one method is really necessary):
@implementation PRButton
- (CGSize)intrinsicContentSize
{
CGRect titleFrameMax = UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(
self.bounds, self.alignmentRectInsets), self.contentEdgeInsets), self.titleEdgeInsets
);
CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(titleFrameMax.size.width, CGFLOAT_MAX)];
CGSize superSize = [super intrinsicContentSize];
return CGSizeMake(
titleSize.width + (self.bounds.size.width - titleFrameMax.size.width),
MAX(superSize.height, titleSize.height + (self.bounds.size.height - titleFrameMax.size.height))
);
}
@end
Swift 4.1.2 Version based on @Jan answer.
import UIKit
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 {
get {
return titleLabel?.intrinsicContentSize ?? CGSize.zero
}
}
override func layoutSubviews() {
super.layoutSubviews()
titleLabel?.preferredMaxLayoutWidth = titleLabel?.frame.size.width ?? 0
super.layoutSubviews()
}
}
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