多行UIButton和自动布局

31 uibutton ios autolayout

我创建了一个看起来像这样的视图控制器:

在此输入图像描述

我希望两个顶部按钮在它们自己和整个视图的左/右边缘之间总是有20个点.它们也应始终具有相同的宽度.我已经为所有这些创建了约束,它完全符合我的要求.问题是垂直约束.按钮应始终位于顶部边缘下方20个点.它们应该具有相同的高度.但是,autolayout不会认为左侧标签需要两行来容纳其所有文本,因此结果如下所示:

在此输入图像描述

我希望它看起来像在第一张照片中.我无法为按钮添加恒定的高度限制,因为当应用程序在iPad上运行时,只需要一行,那么拥有额外的空间将是浪费.

viewDidLoad我试过这个:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.leftButton.titleLabel.preferredMaxLayoutWidth = (self.view.frame.size.width - 20.0 * 3) / 2.0;
    self.rightButton.titleLabel.preferredMaxLayoutWidth = (self.view.frame.size.width - 20.0 * 3) / 2.0;
}
Run Code Online (Sandbox Code Playgroud)

但这并没有改变任何事情.

问题:如何使自动布局尊重左按钮需要两行?

Jan*_*Jan 38

我有同样的问题,我希望我的按钮与其标题一起成长.我不得不对它进行sublcass UIButton,intrinsicContentSize以便它返回标签的内在大小.

- (CGSize)intrinsicContentSize
{
    return self.titleLabel.intrinsicContentSize;
}
Run Code Online (Sandbox Code Playgroud)

由于UILabel是多线的,它intrinsicContentSize是未知的,你必须设置它的preferredMaxLayoutWidth See objc.io文章

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width;
    [super layoutSubviews];
}
Run Code Online (Sandbox Code Playgroud)

其余的布局应该有效.如果您将两个按钮设置为具有相同的高度,则另一个按钮将增长到.完整按钮看起来像这样

@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
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的解决方案!请注意,根据 objc.io 上的文章,子类化时不需要第一个“layoutSubviews”。 (2认同)
  • 由于某种原因,它对我不起作用。它冻结了我的应用程序我用以下方法替换了固有内容大小,并且没有覆盖布局子视图 `override vartrinsicContentSize: CGSize { let labelSize = titleLabel?.sizeThatFits(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) ?? CGSize.zero let reqiredButtonSize = CGSize(width: super.intrinsicContentSize.width, height: labelSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom) return reqiredButtonSize }` (2认同)

use*_*170 19

Swift 4.1.2基于@Jan答案的版本.

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()
    }

}
Run Code Online (Sandbox Code Playgroud)


Yev*_*ska 8

一个对我有用的简单解决方案:通过添加基于标题标签高度的按钮高度约束,使多行按钮在 Swift 4.2 中尊重其标题高度:

let height = NSLayoutConstraint(item: multilineButton,
                                attribute: .height,
                                relatedBy: .equal,
                                toItem: multilineButton.titleLabel,
                                attribute: .height,
                                multiplier: 1,
                                constant: 0)
multilineButton.addConstraint(height)
Run Code Online (Sandbox Code Playgroud)


Les*_*ary 7

这尊重内容边缘插图并为我工作:

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
    }
}
Run Code Online (Sandbox Code Playgroud)


Hog*_*mac 6

添加缺少的约束:

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))
}
Run Code Online (Sandbox Code Playgroud)


Sma*_*rto 1

您是否尝试过使用这个:

self.leftButton.titleLabel.textAlignment = NSTextAlignmentCenter;
self.leftButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail;
self.leftButton.titleLabel.numberOfLines = 0;
Run Code Online (Sandbox Code Playgroud)