UIStackView 中的多行标签
Multiline label in UIStackView
将多行标签(换行符设置为自动换行)放入堆栈视图时,标签会立即失去换行符,而是在一行中显示标签文本。
为什么会发生这种情况以及如何在堆栈视图中保留多行标签?
只需在标签的属性检查器中将行数设置为 0。它会为你工作。
- 首先设置标签行数为0
- 堆栈视图仍然不会增长到
multiLine
,除非你给它一个固定的宽度。当我们固定它的宽度时,当达到该宽度时它会变成多行,如图所示:
如果我们不给堆栈视图一个固定的宽度,那么事情就会变得模棱两可。堆栈视图会随着标签增长多长时间(如果标签值是动态的)?
希望这可以解决您的问题。
正确答案在这里:
- 将
UILabel
嵌入 UIView
(编辑器 -> 嵌入 -> 查看)
- 使用约束使
UILabel
适合 UIView
(例如,尾部 space、顶部 space 和前导 space 到父视图约束)
UIStackView
将拉伸 UIView
以使其适合,UIView
将 UILabel
限制为多行。
iOS 9+
设置 UILabel 的文本后调用 [textLabel sizeToFit]
。
sizeToFit 将使用 preferredMaxWidth 重新布局多行标签。标签将调整 stackView 的大小,这将调整单元格的大小。除了将堆栈视图固定到内容视图之外,不需要其他约束。
对于具有UILabel
作为其视图之一的水平堆栈视图,首先在Interface Builder中设置label.numberOfLines = 0
。这应该允许标签有超过 1 行。当堆栈视图有 stackView.alignment = .fill
时,这最初对我不起作用。要使其工作,只需设置 stackView.alignment = .center
。标签现在可以扩展到 UIStackView
.
中的多行
For all alignments except the fill alignment, the stack view uses each
arranged view’s intrinsicContentSize property when calculating its
size perpendicular to the stack’s axis
注意这里的单词 except。当使用 .fill
时,水平 UIStackView
不会使用排列的子视图的大小垂直调整自身大小。
就我而言,我遵循了之前的建议,但我的文本仍然被截断为单行,尽管只是横向显示。原来,我在标签的文本中发现了一个不可见的 [=10=]
空字符,这是罪魁祸首。它一定是与我插入的破折号符号一起引入的。要查看您的情况是否也会发生这种情况,请使用 View Debugger select 您的标签并检查其文本。
添加UIStackView
属性,
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.axis = .horizontal
请不要在 UIView
内添加标签,您在 UITableViewCell
内使用的不是 required.If,请在旋转时重新加载数据。
以下是 multi-line 标签的 Playground 实现,在 UIStackView
内有一个换行符。它不需要将 UILabel
嵌入任何内容,并且已经过 Xcode 9.2 和 Swift 4 的测试。希望对您有所帮助。
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
将 preferredMaxLayoutWidth 设置为 UILabel 对我有用
self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;
我的魔术是将 widthAnchor
设置为 UIStackView
。
设置 leadingAnchor
和 trailingAnchor
不起作用,但设置 centerXAnchor
和 widthAnchor
可以使 UILabel 正确显示。
系统布局应该弄清楚原点、宽度和高度来绘制它的子视图,在这种情况下你所有的子视图都有相同的优先级,这一点会产生冲突,布局系统不知道视图之间的依赖关系,哪个先绘制, 以此类推
设置堆栈子视图压缩将解决多行问题,具体取决于您的堆栈视图是水平还是垂直以及您希望将哪一个变成多行。 stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal)
lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
Xcode 9.2:
只需将行数设置为0。设置后故事板看起来会很奇怪。别担心运行这个项目。虽然 运行ning 一切都将根据您的故事板设置调整大小。我认为这是情节提要中的一种错误。
提示:最后设置"number of liner to 0"。当你想编辑其他视图时重置它并在编辑后设置为 0。
什么对我有用!
stackview:对齐:填充,分布:填充,约束比例宽度到超级视图 ex。 0.8,
标签:中心,线条 = 0
在尝试了以上所有建议后,我发现 UIStackView 不需要更改任何属性。我只是将 UILabel 的属性更改如下(标签已经添加到垂直堆栈视图中):
Swift 4 例:
[titleLabel, subtitleLabel].forEach(){
[=10=].numberOfLines = 0
[=10=].lineBreakMode = .byWordWrapping
[=10=].setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
}
对于仍然无法使其工作的任何人。尝试在该 UILabel 上设置具有最小字体比例的自动收缩。
Screenshot UILabel Autoshrink settings
这是一个完整的垂直 UIStackView
示例,由具有自动高度的多行 UILabel
组成。
标签基于堆栈视图的宽度换行,堆栈视图的高度基于标签的换行高度。 (使用这种方法,您不需要将标签嵌入 UIView
。) (Swift 5, iOS 12.2)
// 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])
}
}
这几乎就像@Andy 的回答,
但你可以在额外的 UIStackview
中添加你的 UILabel
,垂直对我有用。
对我来说,问题是堆栈视图的高度太短了。标签和堆栈视图已正确设置以允许标签具有多行,但标签是内容压缩的第一个受害者,堆栈视图用来使其高度足够小。
对于那些使用 故事板 或 XIB 文件并试图在水平堆栈视图中嵌入 UILabel 的人,在创建堆栈视图之前,不要向您计划放入堆栈视图的任何内容添加约束。这将导致错误 and/or 无法换行。
相反,除了 Andy and pmb 提出的建议外,还要执行此操作。
- 在
UIView
中嵌入一个 UILabel
。
- 设置
UILabel
行 = 0。
- 创建堆栈视图。
- 将堆栈视图对齐设置为 top/bottom/center。
- 为堆栈视图中的元素添加约束。
不确定为什么这个操作顺序会有所不同,但确实如此。
2020 年 11 月 26 日,Xcode12.2,iOS14.2。
以下适用于我的垂直堆栈视图。它适用于所有设备和模拟器。我使用故事板,所有这些值都在故事板中设置。
UILabel
行数:0
UIStackView
对齐:填充
分布:按比例填充
UILabel 嵌入到视图中并固定到 UIView 的所有边。
在尝试了此页面上的大部分答案后,我的解决方案是根本不使用 UIStackView。
我意识到我并不是真的需要它,只是出于习惯使用它,并且可以用 UIView 完成同样的事情。
您可以在标签中使用带有“\n”和相关 numberOfLines 的 attributedText
将多行标签(换行符设置为自动换行)放入堆栈视图时,标签会立即失去换行符,而是在一行中显示标签文本。
为什么会发生这种情况以及如何在堆栈视图中保留多行标签?
只需在标签的属性检查器中将行数设置为 0。它会为你工作。
- 首先设置标签行数为0
- 堆栈视图仍然不会增长到
multiLine
,除非你给它一个固定的宽度。当我们固定它的宽度时,当达到该宽度时它会变成多行,如图所示:
如果我们不给堆栈视图一个固定的宽度,那么事情就会变得模棱两可。堆栈视图会随着标签增长多长时间(如果标签值是动态的)?
希望这可以解决您的问题。
正确答案在这里:
- 将
UILabel
嵌入UIView
(编辑器 -> 嵌入 -> 查看) - 使用约束使
UILabel
适合UIView
(例如,尾部 space、顶部 space 和前导 space 到父视图约束)
UIStackView
将拉伸 UIView
以使其适合,UIView
将 UILabel
限制为多行。
iOS 9+
设置 UILabel 的文本后调用 [textLabel sizeToFit]
。
sizeToFit 将使用 preferredMaxWidth 重新布局多行标签。标签将调整 stackView 的大小,这将调整单元格的大小。除了将堆栈视图固定到内容视图之外,不需要其他约束。
对于具有UILabel
作为其视图之一的水平堆栈视图,首先在Interface Builder中设置label.numberOfLines = 0
。这应该允许标签有超过 1 行。当堆栈视图有 stackView.alignment = .fill
时,这最初对我不起作用。要使其工作,只需设置 stackView.alignment = .center
。标签现在可以扩展到 UIStackView
.
For all alignments except the fill alignment, the stack view uses each arranged view’s intrinsicContentSize property when calculating its size perpendicular to the stack’s axis
注意这里的单词 except。当使用 .fill
时,水平 UIStackView
不会使用排列的子视图的大小垂直调整自身大小。
就我而言,我遵循了之前的建议,但我的文本仍然被截断为单行,尽管只是横向显示。原来,我在标签的文本中发现了一个不可见的 [=10=]
空字符,这是罪魁祸首。它一定是与我插入的破折号符号一起引入的。要查看您的情况是否也会发生这种情况,请使用 View Debugger select 您的标签并检查其文本。
添加UIStackView
属性,
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.axis = .horizontal
请不要在 UIView
内添加标签,您在 UITableViewCell
内使用的不是 required.If,请在旋转时重新加载数据。
以下是 multi-line 标签的 Playground 实现,在 UIStackView
内有一个换行符。它不需要将 UILabel
嵌入任何内容,并且已经过 Xcode 9.2 和 Swift 4 的测试。希望对您有所帮助。
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
将 preferredMaxLayoutWidth 设置为 UILabel 对我有用
self.myLabel.preferredMaxLayoutWidth = self.bounds.size.width;
我的魔术是将 widthAnchor
设置为 UIStackView
。
设置 leadingAnchor
和 trailingAnchor
不起作用,但设置 centerXAnchor
和 widthAnchor
可以使 UILabel 正确显示。
系统布局应该弄清楚原点、宽度和高度来绘制它的子视图,在这种情况下你所有的子视图都有相同的优先级,这一点会产生冲突,布局系统不知道视图之间的依赖关系,哪个先绘制, 以此类推
设置堆栈子视图压缩将解决多行问题,具体取决于您的堆栈视图是水平还是垂直以及您希望将哪一个变成多行。 stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal)
lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
Xcode 9.2:
只需将行数设置为0。设置后故事板看起来会很奇怪。别担心运行这个项目。虽然 运行ning 一切都将根据您的故事板设置调整大小。我认为这是情节提要中的一种错误。
提示:最后设置"number of liner to 0"。当你想编辑其他视图时重置它并在编辑后设置为 0。
什么对我有用!
stackview:对齐:填充,分布:填充,约束比例宽度到超级视图 ex。 0.8,
标签:中心,线条 = 0
在尝试了以上所有建议后,我发现 UIStackView 不需要更改任何属性。我只是将 UILabel 的属性更改如下(标签已经添加到垂直堆栈视图中):
Swift 4 例:
[titleLabel, subtitleLabel].forEach(){
[=10=].numberOfLines = 0
[=10=].lineBreakMode = .byWordWrapping
[=10=].setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
}
对于仍然无法使其工作的任何人。尝试在该 UILabel 上设置具有最小字体比例的自动收缩。
Screenshot UILabel Autoshrink settings
这是一个完整的垂直 UIStackView
示例,由具有自动高度的多行 UILabel
组成。
标签基于堆栈视图的宽度换行,堆栈视图的高度基于标签的换行高度。 (使用这种方法,您不需要将标签嵌入 UIView
。) (Swift 5, iOS 12.2)
// 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])
}
}
这几乎就像@Andy 的回答,
但你可以在额外的 UIStackview
中添加你的 UILabel
,垂直对我有用。
对我来说,问题是堆栈视图的高度太短了。标签和堆栈视图已正确设置以允许标签具有多行,但标签是内容压缩的第一个受害者,堆栈视图用来使其高度足够小。
对于那些使用 故事板 或 XIB 文件并试图在水平堆栈视图中嵌入 UILabel 的人,在创建堆栈视图之前,不要向您计划放入堆栈视图的任何内容添加约束。这将导致错误 and/or 无法换行。
相反,除了 Andy and pmb 提出的建议外,还要执行此操作。
- 在
UIView
中嵌入一个UILabel
。 - 设置
UILabel
行 = 0。 - 创建堆栈视图。
- 将堆栈视图对齐设置为 top/bottom/center。
- 为堆栈视图中的元素添加约束。
不确定为什么这个操作顺序会有所不同,但确实如此。
2020 年 11 月 26 日,Xcode12.2,iOS14.2。 以下适用于我的垂直堆栈视图。它适用于所有设备和模拟器。我使用故事板,所有这些值都在故事板中设置。
UILabel
行数:0
UIStackView
对齐:填充
分布:按比例填充
UILabel 嵌入到视图中并固定到 UIView 的所有边。
在尝试了此页面上的大部分答案后,我的解决方案是根本不使用 UIStackView。
我意识到我并不是真的需要它,只是出于习惯使用它,并且可以用 UIView 完成同样的事情。
您可以在标签中使用带有“\n”和相关 numberOfLines 的 attributedText