【问题标题】:Autolayout adding extra padding on top and bottom of UILabel iPhone 6/6+ when preferredMaxLayoutWidth is set当设置了 preferredMaxLayoutWidth 时,自动布局在 UILabel iPhone 6/6+ 的顶部和底部添加了额外的填充
【发布时间】:2015-01-11 04:21:03
【问题描述】:

我创建了一个示例项目来重现这一点。

我有一个带有 UILabel 的 xib 文件,它有一个固定的顶部、前导和尾随约束。我添加了一个 minHeight 约束并将行数设置为 0。

我将preferredMaxLayoutWidth 设置为Automatic(在xib 文件中检查)。

在 viewDidLoad 中,我有这个:

self.myLabel.layer.borderColor = [[UIColor redColor] CGColor];
self.myLabel.layer.borderWidth = 2.0f;
self.myLabel.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 ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

当我在 iPhone 6 或 6+ 上运行模拟器时,我得到了这个:

我不知道顶部和底部填充的来源,它与 UILabel 中显示的字符数量成正比。

我忘记了一些神奇的设置吗?它在 iPhone 4" 设备上运行良好。

现在,如果我不设置preferredMaxLayoutWidth,它就没有额外的填充,但这会破坏我在UILabel 中的多行。它切断了文本。我没有使用 Size-Class。

编辑:

因此,我对示例项目进行了一些更改,以匹配我实际项目的情况。我添加了一个 tableView(将顶部、前导、底部和尾随约束设置为其父视图)。 tableView 上的每个单元格都有 4 个标签。顶部标签对单元格的 contentView 具有顶部、前导和尾随约束,随后的标签对其上方的标签具有垂直约束。每个标签都有一个 heightGreaterThan 约束集和一个 widthGreaterThan 集。

这就是没有设置 preferredMaxLayoutWidth 时的样子(注意标签是如何限制为 1 行的)。

使用首选最大布局宽度。现在 UILabel 显示了整个内容,但在顶部和底部都有一个填充。

编辑2: 示例项目:https://www.dropbox.com/s/sdahx9njnsxiv98/MultiLineUILabel.zip?dl=1

【问题讨论】:

  • 我的问题和你一模一样。我什至尝试通过添加几个像素来破解preferredMaxLayoutWidth,但这个数字在很大程度上取决于屏幕的宽度以及在 iPhone 6、iPhone 6+ 和 iPhone 5 上呈现的不同。更不用说 iPad。不确定这是否是一个错误,或者是否有其他一些设置/黑客让它工作。
  • 我也遇到了同样的问题,我没有使用自动布局。该问题仅出现在 iPhone 6 而不是 iPad 上。自动调整大小蒙版设置的组合没有任何区别。最终我通过清理、重启 XCode 和重建解决了这个问题。很奇怪,但它解决了单独清洁无法解决的问题。 XCode 6.1.1.
  • 确保标签的首选宽度设置为自动且未在设置面板上选中显式。这解决了我使用自动布局时的问题。
  • 链接已失效,请更新您的答案

标签: ios objective-c iphone ios8 xib


【解决方案1】:

所以我最终做的是为标签创建一个子类并覆盖 setBounds: 并将preferredMaxLayoutWidth 设置为其边界。

- (void)setBounds:(CGRect)bounds {
    [super setBounds:bounds];

    if (self.preferredMaxLayoutWidth != bounds.size.width) {
        self.preferredMaxLayoutWidth = bounds.size.width;
        [self setNeedsUpdateConstraints];
}}

另外,在 UITableViewCell 子类中,我覆盖了 layoutSubiews

- (void)layoutSubviews {
    [super layoutSubviews];

    [self.contentView layoutIfNeeded];

    // labelsCollection is an IBOutletCollection of my UILabel sublasses
    for (UILabel *label in self.labelsCollection) {
        label.preferredMaxLayoutWidth = label.bounds.size.width;
}}

这一直有效。我认为这种奇怪行为的原因是 UILabel 最初在 xib 文件中设置为 280 像素(320 像素 - 两侧的填充),但在运行时,它会更改其宽度以适应更大的屏幕(因为我设置了前导和尾随约束它增加了将“preferredMaxLayoutWidth”更改为更大值的宽度)。由于某种原因,UILabel 不会将其 preferredMaxLayoutWidth 更新为更大的值,并导致顶部和底部出现空白。

这是我的假设。

希望这会有所帮助。

【讨论】:

  • 我知道这已经过时了,你也迅速做了什么改变吗?因为它没有 setBounds 函数。
  • Nvm 知道了,使用 get & set 并在这些 get & set 中引用 super.bounds 工作正常。
  • @MathijsSegers 你能详细说明你是如何做到这一点的吗?
  • 我必须说它并没有完全“工作”,因为我仍然有所有的间距,但我会发布一个如何在 swift 上实现的答案。我猜人们可以在那里射击。
【解决方案2】:

任何正在研究这个问题的人已经在使用 maxPreferredLayoutWidth(顺便说一句,您不必子类,只需在您的 VC 的 viewDidLayoutSubviews 中设置它)检查您是否将其设置为正确视图的宽度。

我的不工作,因为我有:

label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label1.frame.width

应该是什么时候:

label1.maxPreferredLayoutWidth = label1.frame.width
label2.maxPreferredLayoutWidth = label2.frame.width

你看出区别了吗?我没有 3 小时大声笑

【讨论】:

  • 对于没有看到的任何人......它是label1label2 在第二行中= 标志之后
【解决方案3】:

使用这个类为我修复了它

import UIKit

class CustomLabel: UILabel {

    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size
            super.drawText(in: CGRect(x: 0, y: 0, width: self.frame.width, height: ceil(labelStringSize.height)))
        } else {
            super.drawText(in: rect)
        }
    }

}

【讨论】:

    【解决方案4】:

    UILabel 垂直居中文本。我猜你看到的是你的约束导致标签的视图在更大的设备上拉伸,并且文本正如预期的那样在大小视图上垂直居中。

    您可以尝试将不可编辑的 UITextView 与 UIViewContentModeTop 一起使用。

    【讨论】:

    • 这样会在 textView 的底部添加填充。 TextView 编辑:我应该澄清一下 textView 的高度是在代码中动态设置的,它在 xib 中只有 1 行高。
    • 如果您提前知道文本的大小,您可以在标签上设置高度和宽度限制,并确保其格式符合您的要求。现在我正在查看您的编辑,您是否将换行符设置为自动换行?文本似乎没有按照您想要的方式换行。
    • 这是我最后的手段。理想情况下,我希望自动布局处理它(它在 iPhone 4" 和更小的屏幕上处理得很好)。更改换行符不会改变实际问题(它会改变断行或显示...的位置)。
    【解决方案5】:

    标签底部有什么限制吗?我相信它允许伸展,因为内容拥抱优先级。将其设置为 1000(必需)。这将防止它超出其文本大小。然后,您需要在标签底部添加适当的约束。

    【讨论】:

    • 是的,我有一个从标签到父视图的底部垂直约束(优先级低于其他视图),并且我将水平和垂直内容拥抱优先级设置为 1000。
    • 好的。它几乎看起来就像它计算的高度是针对 4 英寸设备的,但随后宽度被拉伸以用于更大的设备。您可以发布示例项目吗?
    • 当然,dropbox.com/s/sdahx9njnsxiv98/MultiLineUILabel.zip?dl=1 我关闭了preferredMaxLayoutWidth。打开它可以看到多行标签。
    【解决方案6】:

    因为我需要为 iOS 7 兼容性设置 PreferredMaxLayoutWidth,所以我最终调用 boundingRectWithSize 来计算所需的标签高度并为 UILabel 设置暴露的高度约束常量。

    CGRect labelRect = CGRectIntegral([myText boundingRectWithSize:size 
        options:options attributes:attributes context:context]);
    self.myLabelHeightConstraint.constant = labelRect.size.height;
    

    【讨论】:

      【解决方案7】:

      这就是我在 swift 上实现它的方式, 在扩展 UILabel 的类中,我用 getter 和 setter 覆盖了 bounds var,它设置了 super 的 bounds var 并返回它,这样你就可以在 get 和 set 中添加一些代码。

      我必须说我还不相信它正在发挥所有魔力,我仍然有很大的开放空间。

          override var bounds:CGRect {
              get {
                  return super.bounds
              }
              set {
                  super.bounds = newValue
                  if (self.preferredMaxLayoutWidth != super.bounds.size.width) {
                      self.preferredMaxLayoutWidth = super.bounds.size.width;
                      self.setNeedsUpdateConstraints()
                  }
              }
          }
      

      【讨论】:

      • 记录在案,它不会改变高度,如果有人解决了这个问题会很好。让它知道这个话题。
      【解决方案8】:

      首先,伙计们,对不起我的英语。我是英语新手,但我会尝试描述我是如何解决这个问题的。

      我在一些项目中遇到过这个问题。所以我的解决方案是:

      1. 在一个单元格中,我有以下配置方法: -(void)configureWithSomeObject:parentViewSize: 和 tableView:cellForRowAtIndexPath: 我创建了这样的单元格:

        - (UITableViewCell *)tableView:(UITableView *)tableView  cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        YourCell *cell;
        
        //cell initialization
        
        [cell configureWithSomeObject:nil parentViewSize:tableView.frame.size];
        
        return cell;
        }
        
      2. 内部配置方法只是根据父宽度设置preferredMaxLayoutWidth:

         - (void)configureWithSomeObject:(NSObject)someObject parentViewSize:(CGSize)parentViewSize {
        // do your stuff
        
        self.someLabel.preferredMaxLayoutWidth = parentViewSize.width;
         }
        

      附:如果你有前导/尾随空格,你应该从 parentViewSize.width 值中减去它。

      希望它对任何人都有用:)

      【讨论】:

        【解决方案9】:

        我遇到了类似的问题,只是将UILabel 子类化并覆盖setBounds 对我不起作用。单步浏览setBounds 时,我注意到标签的高度为 39.999999993。所以我做了以下更改,将其四舍五入为 40:

        - (void)setBounds:(CGRect)bounds
        {
            bounds.size.height = ceilf(CGRectGetHeight(bounds));
        
            [super setBounds: bounds];
        
            if (self.preferredMaxLayoutWidth != bounds.size.width)
            {
                self.preferredMaxLayoutWidth = bounds.size.width;
                [self setNeedsUpdateConstraints];
            }
        }
        

        这为我修复了它,在大型设备上我的UILabel 上方和下方不再有额外的填充。我也不必设置内容拥抱优先级。

        【讨论】:

          【解决方案10】:

          遇到了这个问题,并且正在浪费时间来解决它。 @AndyC 回答为我做了。我会在这里重复一遍,以防有人错过:

          确保标签的首选宽度设置为自动和显式 没有在设置面板上勾选。这解决了我的问题 使用自动布局

          .

          【讨论】:

            猜你喜欢
            • 2019-11-16
            • 1970-01-01
            • 2017-08-21
            • 2015-10-30
            • 1970-01-01
            • 1970-01-01
            • 2012-07-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多