【问题标题】:UILabel sizeToFit doesn't work with autolayout ios6UILabel sizeToFit 不适用于自动布局 ios6
【发布时间】:2013-04-07 05:26:13
【问题描述】:

我应该如何以编程方式(以及以哪种方法)配置高度取决于其文本的 UILabel?我一直在尝试使用 Storyboard 和代码的组合来设置它,但无济于事。大家推荐sizeToFit,同时设置lineBreakModenumberOfLines。但是,无论我将该代码放在viewDidLoad:viewDidAppear: 还是viewDidLayoutSubviews 中,我都无法让它工作。要么我让长文本框太小,它不会变大,要么我让它太大,它不会缩小。

【问题讨论】:

  • FWIW 相同的代码:我不需要在 Xcode/viewController 中使用label.sizeToFit(),约束就足够了。没有在 Playground 中创建标签。到目前为止,我发现它在 Playground 中工作的唯一方法是 label.sizeToFit()

标签: ios ios6 uilabel autolayout


【解决方案1】:

请注意,在大多数情况下,Matt's solution 会按预期工作。但如果它不适合您,请进一步阅读。

要让您的标签自动调整高度,您需要执行以下操作:

  1. 为标签设置布局约束
  2. 以低优先级设置高度约束。它应该低于 ContentCompressionResistancePriority
  3. 设置 numberOfLines = 0
  4. 将 ContentHuggingPriority 设置为高于标签的高度优先级
  5. 为标签设置preferredMaxLayoutWidth。标签使用该值来计算其高度

例如:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

使用界面生成器

  1. 设置四个约束。高度限制是强制性的。

  2. 然后转到标签的属性检查器并将行数设置为 0。

  3. 转到标签的尺寸检查器并增加垂直 ContentHuggingPriority 和垂直 ContentCompressionResistancePriority。

  4. 选择和编辑高度限制。

  5. 并降低高度限制优先级。

享受吧。 :)

【讨论】:

  • 是的!这正是我一直在寻找的答案。我唯一需要做的就是将 contentHuggingPriority 和 contentCompressionResistancePriority 设置为 required。我可以在IB中做到这一切!非常感谢。
  • 你想多了。设置preferredMaxLayoutWidth 或固定标签的宽度(或其左右两侧)。就这样!然后它将自动垂直增长和收缩以适应其内容。
  • 我必须设置 preferredMaxLayoutWidth 属性 + 固定标签的宽度。像魅力一样工作:)
  • preferredMaxLayoutWidth 和/或固定左右两侧不是绝对的。内容拥抱和压缩优先级将始终有效,只要它们的优先级高于其他约束。
  • ^ 我终于找到了原因,可能值得一提的是,当您将单元格粘在视图底部时,您需要将“to bottom”约束的优先级设置为 less然后 1000 我把它放在 750 上,一切正常。我猜它缩小了视野。
【解决方案2】:
UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));

【讨论】:

    【解决方案3】:

    在 iOS 6 中,使用自动布局,如果 UILabel 的边(或宽度)和顶部被固定,它会自动垂直增长和收缩以适应其内容,根本不需要代码 并且没有弄乱它的抗压性或其他任何东西。这很简单。

    在更复杂的情况下,只需设置标签的preferredMaxLayoutWidth

    无论哪种方式,正确的事情都会自动发生。

    【讨论】:

    • 您还需要确保将 numberOfLines 设置为 0,否则您将无法换行。
    • 这对我来说还不够。还需要@Mark 的回答中的第 2 点。
    • 不写代码也可以让标签自动增长几行?
    • 这比公认的答案要简单得多。我做了两个例子(herehere)来说明这个答案。
    • @Suragch 使用约束这是可行的。但它不适用于 Playground 中的相同代码。在操场上你必须有label.sizeToFit()
    【解决方案4】:

    在 IOS7 中注意到 sizeToFit 也无法正常工作 - 也许该解决方案也可以帮助您

    [textView sizeToFit];
    [textView layoutIfNeeded];
    

    【讨论】:

    • @Rambatino 这对我有用。需要setNeedsUpdateConstraints时添加layoutIfNeeded。但情况可能会有所不同。
    • 当我做一个弹出窗口时,这对我来说效果最好。不过,我需要先做 layoutIfNeeded
    【解决方案5】:

    虽然问题以编程方式说明,遇到了同样的问题,并且更喜欢在 Interface Builder 中工作,但我认为使用 Interface Builder 解决方案添加到现有答案可能会很有用。

    首先要忘记sizeToFit。自动布局将根据内在内容大小代表您处理此问题。

    因此,问题是,如何使用自动布局获取标签以适应其内容?具体来说 - 因为问题提到了它 - 高度。请注意,同样的原则也适用于宽度。

    让我们从一个高度设置为 41px 高的 UILabel 示例开始:

    正如您在上面的屏幕截图中所见,"This is my text" 在上方和下方都有填充。这是 UILabel 的高度和它的内容文本之间的填充。

    如果我们在模拟器中运行应用程序,果然,我们看到的都是一样的:

    现在,让我们在 Interface Builder 中选择 UILabel,并查看 Size 检查器中的默认设置:

    请注意上面突出显示的约束。这就是Content Hugging Priority。正如 Erica Sadun 在出色的 iOS Auto Layout Demystified 中所描述的那样:

    视图倾向于避免围绕其核心内容进行额外填充的方式

    对于我们来说,有了 UILabel,核心内容就是文字。

    这里我们来到了这个基本场景的核心。我们给了我们的文本标签两个约束。他们冲突。有人说“高度必须等于 41 像素高”。另一个说“拥抱它的内容,这样我们就没有任何额外的填充”。在我们的例子中,将视图拥抱它的 text,这样我们就没有任何额外的填充。

    现在,使用自动布局,两个不同的指令说做不同的事情,运行时必须选择一个或另一个。它不能两者兼得。 UILabel 不能同时为 41 像素高, 没有填充。

    解决方法是指定优先级。一条指令必须具有比另一条更高的优先级。如果两条指令说的不同,并且具有相同的优先级,则会发生异常。

    所以让我们试一试吧。我的身高限制的优先级为 1000,这是必需。内容拥抱高度250。如果我们将高度限制优先级降低到 249,会发生什么?

    现在我们可以看到神奇的开始发生了。让我们在 sim 中尝试:

    太棒了!实现内容拥抱。只是因为高度优先级 249 小于内容拥抱优先级 250。基本上,我是说“我在这里指定的高度不如我为内容拥抱指定的高度重要”。所以,拥抱的内容获胜。

    底线,让标签适合文本可以像指定高度或宽度约束一样简单,并正确设置与该轴的内容拥抱优先级约束相关联的优先级。

    将等价的宽度作为练习留给读者!

    【讨论】:

    • 非常感谢您的精彩解释!终于明白内容拥抱优先级了。
    • 能否请您解释一下什么是内容压缩阻力优先级?谢谢!
    • 优秀的回答 Max!有没有办法限制以这种方式工作的行数?
    【解决方案6】:

    在我的例子中,我创建了一个包含 UILabel(长度未知)的 UIView 子类。在 iOS7 中,代码很简单:设置约束,不用担心内容拥抱或压缩阻力,一切都按预期工作。

    但在 iOS6 中,UILabel 总是被剪裁成一行。上面的答案都不适合我。内容拥抱和压缩阻力设置被忽略。防止剪辑的唯一解决方案是在标签上包含一个 preferredMaxLayoutWidth。但是我不知道将首选宽度设置为什么,因为它的父视图的大小是未知的(实际上,它将由内容定义)。

    我终于找到了解决方案here。因为我正在处理自定义视图,所以我可以在计算一次约束后添加以下方法来设置首选布局宽度,然后重新计算它们:

    - (void)layoutSubviews
    {
        // Autolayout hack required for iOS6
        [super layoutSubviews];
        self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
        [super layoutSubviews];
    }
    

    【讨论】:

    • 这正是我遇到的情况……有时很高兴知道你并不孤单。
    • 亚当,我正在为你所说的在 ios7 中完美运行而苦苦挣扎。我有一个带有 uiview 和 uilabel 的自定义单元格。我可以让标签适合内容,但视图不能,无论我对其施加什么限制。你是怎么让它工作的?我发誓我尝试了所有方法,但没有达到标签的高度
    【解决方案7】:

    确保标签的 preferredMaxLayoutWidth 与标签的宽度保持同步的另一个选项:

    #import "MyLabel.h"
    
    @implementation MyLabel
    
    -(void)setBounds:(CGRect)bounds
    {
        [super setBounds:bounds];
    
        // This appears to be needed for iOS 6 which doesn't seem to keep
        // label preferredMaxLayoutWidth in sync with its width, which 
        // means the label won't grow vertically to encompass its text if 
        // the label's width constraint changes.
        self.preferredMaxLayoutWidth = self.bounds.size.width;
    }
    
    @end
    

    【讨论】:

      【解决方案8】:

      我已经解决了 xCode6 将“首选宽度”设置为自动并将标签固定在顶部、前导和尾随

      【讨论】:

        【解决方案9】:

        在我的情况下,当在 UITableViewCell 中使用标签时,标签的大小会调整,但高度会超出表格单元格的高度。这对我有用。我按照 Max MacLeod 做了,然后确保单元格高度设置为 UITableViewAutomaticDimension。

        您可以在您的 init 或 awakeFromNib 中添加它,

        self.tableView.rowHeight = UITableViewAutomaticDimension.  
        

        在情节提要中,选择单元格,打开大小检查器,并通过选中“自定义”复选框确保行高设置为“默认”。

        8.0 中有一个问题也需要在代码中进行设置。

        【讨论】:

          【解决方案10】:

          我在 UIView 子类中也遇到了这个问题,该子类包含一个 UILabel 作为其内部元素之一。即使使用自动布局并尝试了所有推荐的解决方案,标签也不会将其高度收紧到文本。就我而言,我只希望标签是一行。

          无论如何,对我有用的是为 UILabel 添加所需的高度约束,并在调用 intrinsicContentSize 时手动将其设置为正确的高度。如果您没有 UILabel 包含在另一个 UIView 中,您可以尝试子类化 UILabel 并通过首先设置高度约束然后返回
          [super instrinsicContentSize]; 而不是 [ self.containerview intrinsiceContentSize];就像我在下面做的那样,这是特定于我的 UIView 子类的。

          - (CGSize)intrinsicContentSize
          {
              CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
              self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
              return [self.containerView intrinsicContentSize];
          
          }
          

          现在可以在 iOS 7 和 iOS 8 上完美运行。

          【讨论】:

          • 值得注意的是,如果您正确设置了视图(即您的约束是正确的,并且您在视图生命周期的正确阶段设置了所有内容),则永远不必覆盖 @ 987654322@。运行时应该能够根据您正确设置的约束来计算此值。
          • 理论上这应该是正确的,但我们无法访问 Apple 的所有私有 API 和实现,它们并非万无一失,而且代码中确实存在错误。
          • ...但是 [super intrinsicContentSize] 应该照顾它,这就是我的意思。如果您正确实现了自动布局。
          【解决方案11】:

          我觉得我应该做出贡献,因为我花了一段时间才找到正确的解决方案:

          • 我们的目标是让自动布局在不调用 sizeToFit() 的情况下完成其工作,我们将通过指定正确的约束来做到这一点:
          • 在 UILabel 上指定顶部、底部和前导/尾随空格限制
          • 将行数属性设置为 0
          • 将内容拥抱优先级增加到 1000
          • 将内容压缩阻力优先级降低到 500
          • 在底部容器约束中,将优先级降低到 500

          基本上,你会告诉你的 UILabel,即使它有一个固定的高度约束,它也可以打破约束,使自己更小,以便拥抱内容(例如,如果你有单行),但它不能打破约束使其变大。

          【讨论】:

            【解决方案12】:

            我以编程方式添加了UILabel,就我而言,这就足够了:

            label.translatesAutoresizingMaskIntoConstraints = false
            label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
            label.numberOfLines = 0
            

            【讨论】:

              【解决方案13】:

              对我有用的解决方案;如果您的 UILabel 具有固定宽度,请在接口文件中将约束从 constant = 更改为 constant <=

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-12-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多