使用自动布局让文本视图占据整个单元格

Posted

技术标签:

【中文标题】使用自动布局让文本视图占据整个单元格【英文标题】:Getting a text view to take up a whole cell with Auto Layout 【发布时间】:2017-06-16 00:24:23 【问题描述】:

我正在尝试创建一个包含单元格的表格视图,每个单元格都包含一个文本视图,该视图应该占据整个单元格并调整单元格的高度以适合其内容。水平和垂直内容拥抱和抗压优先级是相应设置的。

我已将单元格设置为自动高度

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44

在我的cellForRowAt... 中,我为文本视图的顶部、前导、尾部和底部边缘创建约束,将其约束在单元格的内容视图中。

问题是在运行时文本视图不会占用多行并增加单元格的大小。相反,它会从单元的后缘流出。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
    cell.translatesAutoresizingMaskIntoConstraints = false
    cell.contentView.translatesAutoresizingMaskIntoConstraints = false
    let entry = server.log[indexPath.row]
    let textView = UITextView()
    textView.isScrollEnabled = false
    textView.isEditable = false
    //textView.isUserInteractionEnabled = true
    textView.text = entry.message
    textView.translatesAutoresizingMaskIntoConstraints = false
    cell.contentView.addSubview(textView)

    let top = NSLayoutConstraint(item: textView, attribute: .top, relatedBy: .equal, toItem: cell.contentView, attribute: .topMargin, multiplier: 1.0, constant: 0)
    let leading = NSLayoutConstraint(item: textView, attribute: .leading, relatedBy: .equal, toItem: cell.contentView, attribute: .leadingMargin, multiplier: 1.0, constant: 0)

    let trailing = NSLayoutConstraint(item: textView, attribute: .trailing, relatedBy: .equal, toItem: cell.contentView, attribute: .trailingMargin, multiplier: 1.0, constant: 0)
    let bottom = NSLayoutConstraint(item: textView, attribute: .bottom, relatedBy: .equal, toItem: cell.contentView, attribute: .bottomMargin, multiplier: 1.0, constant: 0)

    //top.priority = 999
    //leading.priority = 999
    trailing.priority = 999
    bottom.priority = 999

    cell.contentView.addConstraints([top, bottom, leading, trailing])

    textView.setContentCompressionResistancePriority(1000, for: .horizontal)
    textView.setContentCompressionResistancePriority(1000, for: .vertical)
    textView.setContentHuggingPriority(1001, for: .horizontal)
    textView.setContentHuggingPriority(1001, for: .vertical)

    return cell;

单元格在运行时的显示方式

框架的显示方式

视图层次调试器报告的内容

【问题讨论】:

【参考方案1】:

您的代码中没有设置UITextView 的高度(或者它的框架)。这意味着 textView 将具有基于您提供的约束的计算框架。您可能想为您的 textView 添加一个 height 约束,看看是否可行。

【讨论】:

由于文本视图的固有内容大小,它已经有一个(self.height = 30 @ 1000 (content size),请参见最后一个屏幕截图)。这个问题的重点是如何让它根据需要使用内在内容大小自动垂直扩展。它与内容压缩和拥抱有关。 您仍然需要为此设置高度限制。类似于textViewHeightConstraint.constant = textView.intrinsicContentSize.height textView.intrinsicContentSize.height 是 30。执行NSLayoutConstraint(item: textView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: textView.intrinsicContentSize.height) 会产生一个与我在上一条评论中提到的自动创建的约束相同的约束。【参考方案2】:

如果可能,我会将您的 UITextView 更改为 UITextField。 然后你可以在代码中做到这一点:

    let example = UITextField()
    example.adjustsFontSizeToFitWidth = true
    example.numberOfLines = 0

在界面生成器中,只需将文本视图的 .numberOfLines 更改为 0。

【讨论】:

这些都是UILabel 属性。 它们也是 uitextview 属性。查看 UIKit 中的 UITextField.h:@property(nonatomic) BOOL adjustsFontSizeToFitWidth; @property(nonatomic) BOOL adjustsFontSizeToFitWidth; // 默认为否。如果是,文本将沿基线缩小到 minFontSize 感谢 ahyattdev,我的手指和大脑不同步。我的意思是 UITextField。【参考方案3】:

According to the documentation

例如,如果文本中没有返回,它会计算 将内容布局为单行所需的高度和宽度 文本。如果你添加约束来指定视图的宽度, 内在内容大小定义显示文本所需的高度 给定它的宽度。

鉴于此,使用固有内容大小的解决方案是设置一个恒定宽度的约束。我也选择使用UILabel,但这也适用于UITextView

let width = NSLayoutConstraint(item: textView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: cell.contentView.frame.width - cell.contentView.layoutMargins.left - cell.contentView.layoutMargins.right)

针对我的特殊情况,我还需要将底部约束的优先级设置为500,并将垂直内容压缩阻力设置为UILayoutPriorityRequired

【讨论】:

以上是关于使用自动布局让文本视图占据整个单元格的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局表格视图时如何增加表格视图单元格中的标签高度(取决于文本)?

iOS 8 中的表格视图单元格自动布局

带有图像和文本字段的自动布局表格单元格?

iOS 自动布局:表格视图单元格宽度 = 0

使用自动布局自定义集合视图单元格的动态高度

在 UITableView 中使用自动布局进行动态单元格布局和可变行高