UIStackView中的多行标签

210
在将具有自动换行设置的多行标签放入堆叠视图中时,该标签立即失去了自动换行功能,并以一行文本的形式显示出来。
为什么会发生这种情况,如何在堆叠视图中保留多行标签?

3
你是否将行数设置为0了? - dasdom
23个回答

280

正确的答案在这里:
https://dev59.com/C1sW5IYBdhLWcg3w-rMA#43110590


  1. UILabel插入到UIView中(Editor->嵌入->视图)
  2. 使用约束将UILabel适配到UIView上(例如,trailing space、top space和leading space至superview约束)

UIStackView会将UIView拉伸以适当地适配界面,并且UIView会将UILabel限制为多行。


57
太蠢了,但它确实起作用!谢谢,伙计!也许有一天苹果会发布一些在他们的SDK中没有半毁的东西...... - Guillaume L.
1
哇,你真是个救星!我已经在做了好几个小时了 :) 记得在属性检查器中将线条设置为0,我刚才漏掉了这一点。 - absin
10
这是解决问题的一种方法,正确的解决方案在这里:https://dev59.com/C1sW5IYBdhLWcg3w-rMA#43110590。 - vietstone
3
只需要将水平对齐方式改为居中,就足以满足我的需求,不需要进行任何 UIView 的花样操作。 - shim
1
@Lucien 这正是此答案中所说的。但正确的答案在这里:https://dev59.com/C1sW5IYBdhLWcg3w-rMA#43110590 - Andy
显示剩余9条评论

256
对于一个水平堆栈视图,其中包含一个UILabel作为其视图之一,在Interface Builder中首先设置label.numberOfLines = 0。这应该允许标签有多行文本。当堆栈视图具有stackView.alignment = .fill时,我最初试图使其工作失败了。为了使其工作,请简单设置stackView.alignment = .center。现在可以通过UIStackView展开多行文本。 Apple documentation说:

对于除填充对齐外的所有对齐方式,堆栈视图在计算垂直于堆栈轴的大小时使用每个已排序视图的intrinsic​Content​Size属性。

请注意此处的except词。当使用.fill时,水平UIStackView不会使用安排的子视图的大小来自动调整自身大小。

7
这是不需要任何技巧的正确解决方案。仔细阅读文档总是值得的! - Islam
3
这应该是被接受的解决方案。在我的情况下,使用UIView的解决方法使UILabel的文本漂浮在另一个子视图上。 - user2061217
30
实际上它不起作用了...我在我的StackView中有3个标签。我将行数设置为0,对齐方式设置为居中...但我仍然看到标签被切断了。 - MatterGoal
11
需要翻译的内容:It's the .alignment of the UIStackView that you have to set to anything but .fill not the UILabel, which is a little confusing in the example given label.alignment = .center. I think this should be stackView.alignment = .center。你需要将UIStackView的.alignment设置为除了.fill以外的任何值,而不是UILabel,这在给出的示例中有点令人困惑,label.alignment = .center。我认为应该是stackView.alignment = .center - ae14
11
如何在垂直的StackView中让多行UILableView正常工作? - DàChún
显示剩余11条评论

47
  • 首先将标签的行数设置为0
  • 如果您不给堆栈视图一个固定的宽度,它仍然不会扩展到multiLine。当我们固定其宽度时,它会在达到该宽度时分成多行,如下所示:

screen recording

如果我们不给堆栈视图一个固定的宽度,那么事情就变得模糊了。堆栈视图会与标签一起增长多长时间(如果标签值是动态的)?

希望这可以解决您的问题。


5
如果堆栈视图的宽度不是固定的,而是与设备(即父视图)的宽度成比例,则怎么办? - OutOnAWeekend
是的,我们也可以有比例宽度。关键是如果标签在某个宽度后必须换行,无论它是什么,都需要定义。 - Irfan
@AnandKumar,你可以在UIViewControllerviewDidLayoutSubviews方法中或者在继承了UIView的子类的layoutSubviews方法中指定标签的preferredMaxLayoutWidth - Shyngys Kassymov
4
这应该是被接受的答案,StackView 的整个意义在于不必在 StackView 和它的元素之间添加约束... - mfaani
7
给定固定值会破坏自动布局的目的。 - Islam
显示剩余3条评论

44

尝试了以上所有建议后,我发现UIStackView不需要更改任何属性。我只需要按照以下方式更改UILabel的属性(标签已经添加到垂直堆栈视图中):

Swift 4 示例:

[titleLabel, subtitleLabel].forEach(){
    $0.numberOfLines = 0
    $0.lineBreakMode = .byWordWrapping
    $0.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
}

3
这是唯一对我起作用的解决方案! - ElectroBuddha
4
我使用了label.setContentCompressionResistancePriority(.fittingSizeLevel, for: .horizontal),它对我很有效。 - Vadim Kurochkin
2
对我有效的唯一方法。太棒了。 - Simon McNeil
2
这应该是被接受的答案。其他解决方案只是绕过问题的方法。 - Haroun Hajem
这是完美的工作解决方案。谢谢。 - Ankit Vyas

39

将preferredMaxLayoutWidth设置为UILabel对我起了作用

self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;

4
这是我的书中的正确答案。每当您处理UILabel并且需要处理多行时,确实需要为其设置一个preferredMaxLayoutWidth(首选最大布局宽度)。没有它可能也可以工作,但在没有它的情况下,事情很快就会变得相当混乱。 - Mof
3
除了你的答案,所有尝试过的答案都是错误的。谢谢! - levan
1
这完美地解决了我的问题,感觉不再像是hacky的东西,谢谢。 - Ethan Zhao
谢谢你的回答!在我的情况下,我的 stackView 的对齐方式已经设置为 .center,我真的不需要把标签放在 UIView 内部。 - Fariza Zhumat

14

在属性检查器中,将标签的行数设置为0即可。这对你有用。

输入图片描述


20
对于一个垂直的StackView,你需要将Distribution设置为“Fill”才能使其正常工作。 - SnoopyProtocol
4
将分布设置为“填充”是解决的关键。 - Dylan Moore
1
我发现在一个垂直UIStackView中,我必须为UILabel子视图设置顶部和底部约束以扩展并显示所有文本。 - bruce1337

7

2020年11月26日,Xcode 12.2,iOS 14.2。

以下对于我来说适用于垂直堆栈视图。它在所有设备和模拟器上都有效。我使用storyboard,并且所有这些值都在storyboard中设置。

UILabel

行数:0

UIStackView

对齐方式:填充

分配:按比例填充

UILabel嵌入在一个视图中,并固定到UIView的所有边缘。


只需将UILabel嵌入视图中并将其固定在UIView的所有边缘即可!谢谢。 - Raja Saad

6

iOS 9+

在设置UILabel的文本后,调用[textLabel sizeToFit]方法。

sizeToFit将使用preferredMaxWidth重新布局多行标签。该标签将调整stackView的大小,从而调整单元格的大小。除了将stackView固定到contentView之外,不需要任何其他约束条件。


5

以下是一个完整的垂直 UIStackView 示例,由多行的自动高度UILabel组成。

标签根据StackView的宽度换行,StackView的高度基于标签的换行高度。(使用这种方法,您不需要将标签嵌入到UIView中。)(Swift 5,iOS 12.2)

enter image description here

// A vertical stackview with multiline labels and automatic height.
class ThreeLabelStackView: UIStackView {
    let label1 = UILabel()
    let label2 = UILabel()
    let label3 = UILabel()

    init() {
        super.init(frame: .zero)
        self.translatesAutoresizingMaskIntoConstraints = false
        self.axis = .vertical
        self.distribution = .fill
        self.alignment = .fill

        label1.numberOfLines = 0
        label2.numberOfLines = 0
        label3.numberOfLines = 0
        label1.lineBreakMode = .byWordWrapping
        label2.lineBreakMode = .byWordWrapping
        label3.lineBreakMode = .byWordWrapping
        self.addArrangedSubview(label1)
        self.addArrangedSubview(label2)
        self.addArrangedSubview(label3)

        // (Add some test data, a little spacing, and the background color
        // make the labels easier to see visually.)
        self.spacing = 1
        label1.backgroundColor = .orange
        label2.backgroundColor = .orange
        label3.backgroundColor = .orange
        label1.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi."
        label2.text = "Hello darkness my old friend..."
        label3.text = "When I wrote the following pages, or rather the bulk of them, I lived alone, in the woods, a mile from any neighbor, in a house which I had built myself, on the shore of Walden Pond, in Concord, Massachusetts, and earned my living by the labor of my hands only."
    }

    required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

这里是一个使用它的示例ViewController
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let myLabelStackView = ThreeLabelStackView()
        self.view.addSubview(myLabelStackView)

        // Set stackview width to its superview.
        let widthConstraint  = NSLayoutConstraint(item: myLabelStackView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1, constant: 0)
        self.view.addConstraints([widthConstraint])
    }
}

这似乎是我情况下的解决方案。垂直UIStackView包含多个UILabel,其中一个具有多行文本。我将此SV的宽度设置为单元格宽度的比例。就这样。 - MkVal

5
我的魔法技巧是为UIStackView设置widthAnchor。 设置leadingAnchortrailingAnchor不会起作用,但设置centerXAnchorwidthAnchor可以使UILabel正确显示。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接