Multiline label in UIStackView

2019-01-12 22:10发布

问题:

When putting multiline label (with linebreak set to Word Wrap) into a stack view, the label immediately loses the linebreak and displays the label text in one line instead.

Why is this happening and how does one preserve multiline label within a stack view?

回答1:

  1. Embed the UILabel inside a UIView (Editor -> Embed In -> View)
  2. Use constraints to fit the UILabel to the UIView (for example, trailing space, top space, and leading space to superview constraints)

The UIStackView will stretch out the UIView to fit properly, and the UIView will constrain the UILabel to multiple lines.



回答2:

For a horizontal stack view that has a UILabel as one of its views, in Interface Builder firstly set label.numberOfLines = 0. This should allow the label to have more than 1 line. This initially failed to work for me when the stack view had label.alignment = .fill. To make it work simply set label.alignment = .center. The label can now expand to multiple lines within the UIStackView.

The Apple documentation says

For all alignments except the fill alignment, the stack view uses each arranged view’s intrinsic​Content​Size property when calculating its size perpendicular to the stack’s axis

Note the word except here. When .fill is used the horizontal UIStackView does NOT resize itself vertically using the arranged subviews sizes.



回答3:

  • First set the label number of lines to 0
  • The stack view still won't grow to multiLine unless you give it a fixed width. When we fix its width then it break to multiline when that width is reached as shown:

If we don't give a fixed width to the stack view then things get ambiguous. How long will the stack view grow with the label (if the label value is dynamic)?

Hope this can fix your issue.



回答4:

Just set number of lines to 0 in Attribute inspector for label. It will work for you.



回答5:

The following is a Playground implementation of multi-line label with a line break inside a UIStackView. It doesn't require embedding the UILabel inside anything and has been tested with Xcode 9.2 and Swift 4. Hope it's helpful.

import UIKit
import PlaygroundSupport

let containerView = UIView()
containerView.frame = CGRect.init(x: 0, y: 0, width: 400, height: 500)
containerView.backgroundColor = UIColor.white

var label = UILabel.init()
label.textColor = .black
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "This is an example of sample text that goes on for a long time. This is an example of sample text that goes on for a long time."

let stackView = UIStackView.init(arrangedSubviews: [label])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
containerView.addSubview(stackView)
stackView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: containerView.widthAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true

PlaygroundPage.current.liveView = containerView


回答6:

Add UIStackView properties,

stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.axis = .horizontal

Instead of adding label inside UIView which is not required.If you are using inside UITableViewCell please, reload data on rotation.



回答7:

Setting preferredMaxLayoutWidth to the UILabel worked for me

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


回答8:

iOS 9+

Call [textLabel sizeToFit] after setting the UILabel's text.

sizeToFit will re-layout the multiline label using preferredMaxWidth. The label will resize the stackView, which will resize the cell. No additional constraints besides pinning the stack view to the content view are required.



回答9:

The magic trick for me was to set a widthAnchor to the UIStackView.

Setting leadingAnchor and trailingAnchor won't work, but setting centerXAnchor and widthAnchor made the UILabel display correctly.



回答10:

In my case, I followed the previous suggestions, but my text was still getting truncated to a single line though only in landscape. Turns out, I found an invisible \0 null character in the label's text which was the culprit. It must have been introduced alongside the em dash symbol I had inserted. To see if this is also happening in your case, use the View Debugger to select your label and inspect its text.



回答11:

System layout should figure out origin, width and height to draw it subviews, in this case all of your subviews has same priority, that point make conflict, layout system don't known dependencies between views, which one draw first, second and so on

Set stack subviews compression will solve problem with multiple line, depending on your stack view is horizontal or vertical and which one you want to become multiple lines. stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal) lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)



回答12:

Xcode 9.2:

Just set number of lines to 0. Storyboard will look weird after setting this. Don't worry run the project. While running everything will resize according to your storyboard setup. I think its kind of bug in storyboard.

Tips : Set "number of liner to 0" in the last. reset it when you want to edit some other view and set to 0 after editing.



回答13:

What worked for me!

stackview: alignment: fill, distribution: fill, constraint proportional width to superview ex. 0.8,

label: center, and lines = 0