使用自动布局中的多行UIButtons设置UITableViewCell高度

时间:2015-06-30 07:24:12

标签: ios objective-c swift uitableview autolayout

我有UITableView个自定义UITableViewCell,每个内部都有一个UIButton。我设置按钮'数组中的标题,因此按钮的大小根据标题而变化。我需要根据heightForRowAtIndexPath事件中内部按钮的大小返回正确的高度。

由于我使用自动布局,我已经为按钮的高度限制创建了一个插座,并且我在单元格中layoutSubviews()更新了它。像这样的事件:

class CustomCell: UITableViewCell {

    /* ... */

    override func layoutSubviews() {
        super.layoutSubviews()
        self.myButton?.layoutIfNeeded()
        self.heightConstraint?.constant = self.myButton!.titleLabel!.frame.size.height
    }
}

然后我根据按钮高度和上下边距返回高度,如下所示:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomCell
    cell.myButton?.setTitle(self.data[indexPath.row], forState: UIControlState.Normal)
    cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds))
    cell.setNeedsLayout()
    cell.layoutIfNeeded()
    return cell.myButton!.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + (cell.topMarginConstraint!.constant * 2) /* top-bottom margins */ + 1 /* separator height */
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomCell
    cell.myButton?.setTitle(self.data[indexPath.row], forState: UIControlState.Normal)
    return cell
}

首次发布时,似乎没有问题。但是,在我开始滚动之后,某些行的高度似乎是错误的。当我回到顶部时,我发现之前的细胞高度也会被打破。

当我搜索类似的问题时,问题似乎是关于可重复使用的细胞,尽管我无法找到另一种计算高度的方法。可以通过另一种方法正确地重复使用细胞或获得正确的高度可以做些什么?

更多信息和源代码:

IB设定的约束如下:

Constraints SS

这是第一次发布的细胞:

Correct cell heights SS

经过一些滚动:

Broken cell heights SS

项目的完整代码可在Github上找到。

3 个答案:

答案 0 :(得分:1)

首先,如果你在UIView的func updateConstraints()方法中执行约束更新会更好。而不是

override func layoutSubviews() {
        super.layoutSubviews()
        self.myButton?.layoutIfNeeded()
        self.heightConstraint?.constant = self.myButton!.titleLabel!.frame.size.height
}

我愿意

override func updateConstraints() {
        self.myButton?.layoutIfNeeded()
        self.heightConstraint?.constant = self.myButton!.titleLabel!.frame.size.height
        super.updateConstraints()
}

请注意,您应该在结束时调用超级实现,而不是在开始时调用。然后,您可以调用cell.setNeedsUpdateConstraints()来触发约束更新传递。

此外,你永远不应该像heightForRowAtIndePath:方法那样直接操作单元格边界,即使你完全确定直接操作就是你想要的,你应该操纵cell.contentView的边界,而不是cell的边界。如果要根据内容的尺寸动态调整单元格高度,则应使用自定义单元格。如果您需要支持iOS 7,那么this answer会告诉您如何仅使用autolayout实现该行为(不触及边界等)。

重申答案,你应该这样做:

func viewDidLoad() {
    self.dummyCell = CustomCell.init()
    // additional setup
}

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    self.dummyCell.myButton?.setTitle(self.data[indexPath.row], forState: UIControlState.Normal)
    self.dummyCell.layoutIfNeeded() // or self.dummyCell.setNeedsUpdateConstraints() if and only if the button text is changing in the cell
    return self.dummyCell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
}

请知道我链接的答案概述了通过自动布局获取单元格高度的策略,因此只编写我提出的代码更改是不够的,除非您以使该解决方案有效的方式设置约束。有关更多信息,请参阅该答案。  希望它有所帮助!

答案 1 :(得分:0)

根据this

将tableView配置为

func configureTableView() {
  tableView.rowHeight = UITableViewAutomaticDimension
  tableView.estimatedRowHeight = 160.0
}
  1. 在viewDidLoad方法

  2. 上调用它
  3. 将您的uibutton高度约束配置为大于或等于。

  4. 覆盖func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat,您可以在其中放置估算高度代码

答案 2 :(得分:0)

首先,删除按钮的高度约束并将其与单元格的顶部和底部绑定。

然后,在你的手机中'高度,根据按钮的宽度和字体计算文本的高度。这将使单元格的高度变得动态,您不再需要高度约束。

请参阅以下链接以获取文字的高度: Adjust UILabel height to text

希望它有所帮助。如果您需要进一步的帮助或了解任何事情,请告诉我.. :)