UIStackView 中的多行标签

Posted

技术标签:

【中文标题】UIStackView 中的多行标签【英文标题】:Multiline label in UIStackView 【发布时间】:2016-03-26 23:41:41 【问题描述】:

当将多行标签(换行设置为自动换行)放入堆栈视图时,标签会立即失去换行并在一行中显示标签文本。

为什么会发生这种情况?如何在堆栈视图中保留多行标签?

【问题讨论】:

你把行数设置为0了吗? 【参考方案1】:

只需在标签的属性检查器中将行数设置为 0。它会为你工作。

【讨论】:

对于垂直 stackView,您需要将 Distribution 设置为“Fill”才能正常工作。 将分布设置为“填充”是修复的关键。 我发现对于垂直 UIStackView,我必须为子 UILabel 设置顶部和底部约束才能展开并显示所有文本。【参考方案2】: 先将标签行数设置为0 堆栈视图仍然不会增长到multiLine,除非你给它一个固定的宽度。当我们固定它的宽度时,它会在达到该宽度时变为多行,如下所示:

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

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

【讨论】:

如果堆栈视图的宽度不是固定的,而是与设备(即超级视图)的宽度成比例。 是的,我们也可以有一个比例宽度。关键是标签是否必须在一定宽度后中断,但需要定义。 @AnandKumar 您可以在viewDidLayoutSubviews 中为您的标签指定preferredMaxLayoutWidthUIViewControllerlayoutSubviews 如果您是UIView 的子类。 这应该是公认的答案,stackview 的重点是不必在 stackview 及其元素之间添加约束... 给出一个固定值违背了自动布局的目的【参考方案3】:

正确答案在这里:https://***.com/a/43110590/566360


    UIView 中嵌入UILabel(编辑器-> 嵌入-> 视图) 使用约束使 UILabel 适合 UIView(例如,尾随空格、顶部空格和前导空格以适应超级视图约束)

UIStackView 将延伸 UIView 以正确适应,UIViewUILabel 限制为多行。

【讨论】:

这很愚蠢,但它有效!谢啦 !也许有一天,Apple 会发布一些在他们的 SDK 中还没有损坏的东西…… 天哪!你是救世主!我已经做了几个小时了 :) 记得在 Attributes Inspector 中也将行设置为 0,只是缺少了那个。 这是解决方法,正确的解决方案在这里***.com/a/43110590/566360 对我来说只需将水平对齐更改为中心就足够了。不需要UIView 恶作剧。 @Lucien 这正是这个答案中所说的。但正确答案在这里:***.com/a/43110590/566360【参考方案4】:

ios 9+

设置 UILabel 的文本后调用[textLabel sizeToFit]

sizeToFit 将使用preferredMaxWidth 重新布局多行标签。标签将调整 stackView 的大小,这将调整单元格的大小。除了将堆栈视图固定到内容视图之外,不需要其他约束。

【讨论】:

【参考方案5】:

对于将UILabel 作为其视图之一的水平堆栈视图,在Interface Builder 中首先设置label.numberOfLines = 0。这应该允许标签有超过 1 行。当堆栈视图有stackView.alignment = .fill 时,这最初对我不起作用。要使其正常工作,只需设置stackView.alignment = .center。标签现在可以扩展到UIStackView 中的多行。

Apple documentation 说

对于除填充对齐之外的所有对齐,堆栈视图使用每个 排列视图的内在​Content​Size 属性在计算其 垂直于栈轴的大小

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

【讨论】:

这是没有黑客攻击的正确解决方案。阅读文档总是有回报的! 这应该是公认的解决方案。在我的情况下,使用 UIView 解决方法 UILabel 的文本漂浮在另一个子视图上。 它实际上不起作用...我的堆栈视图中有 3 个标签。我已将线条设置为零并将对齐设置为中心...我仍然看到标签被剪掉了。 UIStackView 的 .alignment 必须设置为除 .fill 之外的任何内容.我认为这应该是stackView.alignment = .center 但是如何让多行 UILableView 在垂直 StackView 中工作?【参考方案6】:

就我而言,我遵循了之前的建议,但我的文本仍然被截断为一行,尽管只是在横向中。事实证明,我在标签的文本中发现了一个不可见的 \0 空字符,这是罪魁祸首。它一定是在我插入的破折号符号旁边引入的。要查看您的情况是否也发生这种情况,请使用 View Debugger 选择您的标签并检查其文本。

【讨论】:

【参考方案7】:

添加UIStackView属性,

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

不要在UIView 内添加标签,这不是必需的。如果您在UITableViewCell 内使用,请在旋转时重新加载数据。

【讨论】:

【参考方案8】:

以下是多行标签的 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

【讨论】:

【参考方案9】:

将 preferredMaxLayoutWidth 设置为 UILabel 对我有用

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

【讨论】:

这是我书中的正确答案。当你弄乱了 UILabel 并需要处理多行时,你真的需要给它一个 preferredMaxLayoutWidth。没有它它可能会工作,但如果没有它,事情很快就会变得相当时髦。 所有人都尝试了所有答案,除了你的答案之外,所有答案都是错误的。谢谢! 这完美解决了我的问题,感觉不那么老套了,谢谢。 感谢您的回答!在我的情况下,我的 stackView 的对齐方式已经设置为 .center,我真的不需要 UIView 中的标签。【参考方案10】:

对我来说,魔术是将widthAnchor 设置为UIStackView

设置leadingAnchortrailingAnchor 将不起作用,但设置centerXAnchorwidthAnchor 可以正确显示UILabel。

【讨论】:

【参考方案11】:

系统布局应该计算出原点,宽度和高度来绘制它的子视图,在这种情况下,你所有的子视图都有相同的优先级,这点会产生冲突,布局系统不知道视图之间的依赖关系,哪个先绘制,第二个绘制等等

设置堆栈子视图压缩将解决多行问题,具体取决于您的堆栈视图是水平还是垂直以及您希望哪一个成为多行。 stackOtherSubviews .setContentCompressionResistancePriority(.defaultHight, for: .horizontal) lblTitle.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

【讨论】:

【参考方案12】:

Xcode 9.2:

只需将行数设置为 0。设置后情节提要看起来很奇怪。不用担心运行项目。运行时,所有内容都会根据您的故事板设置调整大小。我认为这是情节提要中的一种错误。

Tips : 最后设置"number of liner to 0"。当您想编辑其他视图时重置它并在编辑后设置为 0。

【讨论】:

【参考方案13】:

什么对我有用!

stackview:对齐:填充,分布:填充,约束比例宽度到超级视图前。 0.8,

标签:中心,线 = 0

【讨论】:

【参考方案14】:

在尝试了上述所有建议后,我发现 UIStackView 不需要更改属性。我只是将 UILabels 的属性更改如下(标签已添加到垂直堆栈视图中):

Swift 4 示例:

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

【讨论】:

这是唯一对我有用的解决方案! 我用过label.setContentCompressionResistancePriority(.fittingSizeLevel, for: .horizontal) 它对我有用。 唯一对我有用的东西。太棒了【参考方案15】:

对于仍然无法使其工作的任何人。尝试在该 UILabel 上使用最小字体比例设置 Autoshrink。

Screenshot UILabel Autoshrink settings

【讨论】:

考虑通过代码示例改进您的答案。 @fridoo 添加了设置截图。【参考方案16】:

这是一个垂直UIStackView 的完整示例,它由具有自动高度的多行UILabels 组成。

标签的换行基于stackview 的宽度,stackview 的高度基于标签的换行高度。 (使用这种方法,您不需要在 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])
    

【讨论】:

这似乎是我的解决方案。包含多个 UILabel 的垂直 UIStackView,其中一个具有多行文本。我将此 SV 的宽度设置为与单元格的宽度成比例。就是这样。【参考方案17】:

这几乎就像@Andy 的回答, 但是您可以在额外的UIStackview 中添加您的UILabel,垂直为我工作。

【讨论】:

【参考方案18】:

对我来说,问题是堆栈视图的高度太短了。标签和堆栈视图已正确设置以允许标签具有多行,但标签是内容压缩的第一个受害者,堆栈视图用于使其高度足够小。

【讨论】:

【参考方案19】:

对于那些使用 storyboardXIB 文件并试图在水平堆栈视图中嵌入 UILabel 的人,不要对您计划的任何内容添加约束在创建堆栈视图之前放入堆栈视图。这将导致错误和/或无法换行。

除了Andy and pmb 提出的建议之外,请执行此操作。

    UIView 中嵌入UILabel。 设置UILabellines = 0。 创建堆栈视图。 将堆栈视图对齐设置为顶部/底部/中心。 为堆栈视图中的元素添加约束。

不确定为什么这种操作顺序会有所不同,但确实如此。

【讨论】:

【参考方案20】:

2020 年 11 月 26 日,Xcode 12.2,iOS 14.2。 以下适用于我的垂直堆栈视图。它适用于所有设备和模拟器。我使用情节提要,所有这些值都在情节提要中设置。

UILabel

行数:0

UIStackView

对齐:填充

分布:按比例填充

UILabel 嵌入在视图中,并固定到 UIView 的所有侧面。

【讨论】:

这对我来说非常有用,谢谢!【参考方案21】:

在尝试了此页面上的大多数答案后,我的解决方案是根本不使用 UIStackView。

我意识到我并不真正需要它,只是出于习惯使用它,并且可以使用 UIView 完成同样的事情。

【讨论】:

【参考方案22】:

您可以在标签中使用带 "\n" 和相关 numberOfLines 的属性文本

【讨论】:

这在任何设备的屏幕上都无法正常工作。

以上是关于UIStackView 中的多行标签的主要内容,如果未能解决你的问题,请参考以下文章

UIStackView 中的多行 UILabel 问题

UITableViewCell 中的 UIStackView 与多行 UILabel

iOS:多行 UILabel 与水平 UIStackView 中的另一个 UILabel 大小错误

多行标签和带有 UIStackView 的图像

UIStackView 和多行标签?

UITableViewCell 中带有多行标签的 UIStackView 高度不正确