【问题标题】:Update cell height after it is rendered渲染后更新单元格高度
【发布时间】:2017-09-01 12:46:02
【问题描述】:

我已经用UITableViewAutomaticDimension 设置了UITableViewCell
TableViewCell 中嵌入了一个 UICollectionView,它不可滚动,但可以根据 collectionview 的内容具有可变的高度。

现在我尝试的是渲染单元格并将集合视图的高度约束分配给变量collectionViewHeightConstraint,然后在 layoutSubviews 方法中渲染集合视图后更新高度

override func layoutSubviews() {
    super.layoutSubviews()
    self.collectionViewHeightConstraint?.constant = self.collectionView!.contentSize.height
}

这是 collectionview 约束的样子(使用制图):

    self.contentView.addSubview(self.collectionview)   
    self.contentView.addSubview(self.holdingView)
    constrain(self.holdingView!, self.contentView) {
        holderView, container in
        holderView.top == container.top
        holderView.left == container.left
        holderView.right == container.right
        holderView.bottom == container.bottom
    }
    constrain(self.collectionView!, self.holdingView) {
        collectionView, containerView in
        collectionView.top == containerView.top
        collectionView.left == containerView.left
        collectionView.right == containerView.right
        collectionViewHeightConstraint = collectionView.height == collectionViewHeight
        containerView.bottom == collectionView.bottom
    }

但这似乎并没有更新单元格高度。

有什么方法可以更新吗?

编辑
这不是某些人建议的重复问题,为什么在下面的 cmets 中进行了解释。

【问题讨论】:

  • 在设置高度后尝试重新加载UITableView 并检查heightConstant != contentSize 是否存在。使用它来检查UICollectionView 的高度是否正确更新。
  • @Rikh :这听起来像是一个解决方案,但也非常混乱和骇人听闻。我的意思是,如果没有别的,这就是我会去的。
  • 好吧,你确实需要通知你的UITableView 重新计算它的高度,只有在你知道你更新了哪个集合视图的情况下,你总是可以尝试重新加载特定的行(如果你不想重新加载整个UITableView)!
  • @Rikh 它仍然很混乱,因为 layoutsubviews 被多次调用,有时内容高度为 0

标签: ios swift uitableview cocoa-touch xib


【解决方案1】:

由于评论空间太小,我将所有内容都放在这里:

注意:您实际上不必在viewDidLayoutSubviews 中设置高度限制,只要您可以确定UICollectionView 已设置并且您的布局已在您的整个屏幕上正确设置!例如,在viewDidAppear 中执行此操作,然后调用layoutIfNeeded() 也可以。仅当您在调用viewDidAppear 之前设置了UICollectionView,即您事先知道您的UICollectionView 数据源,将其移至viewDidAppear 才有效。

修复 1:

设置高度后尝试重新加载 UITableView 并检查 heightConstant != contentSize 是否存在。使用它来检查 UICollectionView 的高度是否正确更新,即:

override func layoutSubviews() {
    super.layoutSubviews()

    if self.collectionViewHeightConstraint?.constant != self.collectionView!.contentSize.height{

        self.collectionViewHeightConstraint?.constant = self.collectionView!.contentSize.height

        //to make sure height is recalculated
        tableView.reloadData()
        //or reload just the row depending on use case and if you know the index of the row to reload :)
    }
}

我同意你的评论,但它很混乱,我的意思是用它作为修复和/或检查问题是否真的出在哪里!

至于为什么它是0,这可能是因为你的UICollectionView还没有被设置(cellForItem还没有被调用)所以contentSize实际上没有被计算!

修复 2:

一旦设置了UICollectionViewdataSource,即您接收到数据,您将手动计算UICollectionView contentSize 的高度并设置一次并重新加载行。如果计算是一项繁琐的任务,只需设置 dataSource 并在UICollectionView 上调用 reloadData。这将确保正确设置UICollectionView,然后将单元格的约束设置为contentSize,并在UITableView 上调用reloadDatareloadRow

您基本上可以在您的UICollectionView 设置并且您的视图已布置之后随时设置 heightConstraint。之后你只需要打电话给tableView.reloadData()

【讨论】:

  • 您不必调用tableView.reloadData() 来确保重新计算高度,tableView.beginUpdates(); tableView.endUpdates() 应该足够了
  • @crizzis 我在下面的帖子中意识到了这一点:)。但老实说,我发现 reloadData() 总是提供所需的结果,而不是 beginUpdates()(也许我只是做得不对 D:) 而且你并不总是希望提供动画。跨度>
  • @Rikh 您能否更新答案以更新单个单元格或使用委托调用具有该单元格索引的 tableview 对象来更新该单元格,而不是为每个单元格更新整个表格
【解决方案2】:

按照你的要求,我想如果我们先加载collectionview,然后用collectionview的正确高度加载tableview,我们可以解决这个问题。

collectionView.reloadData()
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.collectionViewHeightConstraint?.constant = self.collectionView!.contentSize.height
        })
tableview.reloadData()

这样,当 tableview 加载时,单元格具有基于集合视图内容大小的所需高度。

【讨论】:

  • collectionViewHeightConstraint 在单元格中。您是要我从单元格内部重新加载表格视图吗?除此之外,这将重新启动整个渲染过程,重置约束值
  • 重新加载collectionview的调用应该在tableviews cellForRowAtIndexPath中对吧?您如何在单元格中添加该代码,一旦完成,您应该具有所需的高度。另外我建议确保上面的代码只运行一次,否则它会减慢应用程序,因为 cellForRowAtIndexPath 被多次调用
【解决方案3】:

您可以重新加载表格视图的特定单元格

let indexPath = IndexPath(item: rowNumber, section: 0)
    tableView.reloadRows(at: [indexPath], with: .top)

【讨论】: