I have created a view controller that looks like this:
I want the two
add the missing constraints:
if let label = button.titleLabel {
button.addConstraint(NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: button, attribute: .top, multiplier: 1.0, constant: 0.0))
button.addConstraint(NSLayoutConstraint(item: label, attribute: .bottom, relatedBy: .equal, toItem: button, attribute: .bottom, multiplier: 1.0, constant: 0.0))
}
Version, which also taking into account titleEdgeInsets
and not overrides standard button behaviour unless titleLabel?.numberOfLines
set to zero
and button image set to nil
.
open class Button: UIButton {
override open var intrinsicContentSize: CGSize {
if let titleLabel = titleLabel, titleLabel.numberOfLines == 0, image == nil {
let size = titleLabel.intrinsicContentSize
let result = CGSize(width: size.width + contentEdgeInsets.horizontal + titleEdgeInsets.horizontal,
height: size.height + contentEdgeInsets.vertical + titleEdgeInsets.vertical)
return result
} else {
return super.intrinsicContentSize
}
}
override open func layoutSubviews() {
super.layoutSubviews()
if let titleLabel = titleLabel, titleLabel.numberOfLines == 0, image == nil {
let priority = UILayoutPriority.defaultLow + 1
if titleLabel.horizontalContentHuggingPriority != priority {
titleLabel.horizontalContentHuggingPriority = priority
}
if titleLabel.verticalContentHuggingPriority != priority {
titleLabel.verticalContentHuggingPriority = priority
}
let rect = titleRect(forContentRect: contentRect(forBounds: bounds))
titleLabel.preferredMaxLayoutWidth = rect.size.width
super.layoutSubviews()
}
}
}
UPDATED Swift/Swift 2.0 version again based on @Jan's answer
@IBDesignable
class MultiLineButton:UIButton {
//MARK: -
//MARK: Setup
func setup () {
self.titleLabel?.numberOfLines = 0
//The next two lines are essential in making sure autolayout sizes us correctly
self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, forAxis: .Vertical)
self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, forAxis: .Horizontal)
}
//MARK:-
//MARK: Method overrides
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
override func intrinsicContentSize() -> CGSize {
return self.titleLabel!.intrinsicContentSize()
}
override func layoutSubviews() {
super.layoutSubviews()
titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width
}
}
Lot of answers here, but the simple one by @Yevheniia Zelenska worked fine for me. Simplified Swift 5 version:
@IBOutlet private weak var button: UIButton! {
didSet {
guard let titleHeightAnchor = button.titleLabel?.heightAnchor else { return }
button.heightAnchor.constraint(equalTo: titleHeightAnchor).isActive = true
}
}
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
}
}
Have you tried using this:
self.leftButton.titleLabel.textAlignment = NSTextAlignmentCenter;
self.leftButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail;
self.leftButton.titleLabel.numberOfLines = 0;