iOS8更改dynamic单元格的高度“现在”,重新设置内部单元格内容

这是一个dynamic的单元格

在这里输入图像说明

注意 – 在这个例子中,文本不是数据驱动的。 这只是一些本地的单元格文本(例如,帮助文本)。 在运行时,使用单元格内的button,将UILabel的.text从一个单词改为多行。 iOS正确调整单元格和表的大小…

…但只有当单元格在屏幕外滚动,然后再次打开

如何提醒表视图重新计算“现在”的一切?


(请注意,这个问题只适用于dynamic单元格高度的iOS8 +,Xcode7 +自动布局。)

我假设你不是在cellForRowAtIndexPath设置UILabeltext属性,而是在其他地方(或者是asynchronous执行)。 如果是这样的话,我不会更新那里的用户界面。 相反,我会更新支持该表的模型,然后调用reloadRowsAtIndexPaths 。 这将使cellForRowAtIndexPath再次调用,但不像重新加载整个表,这将优雅地保持tableview的contentOffset正确的位置。

我知道这一切听起来不必要的复杂,但底线是,你不拥有这个观点,表视图。 除了更新单元之外,它还要做各种各样的东西。 也就是说,如果细胞增长,找出哪些细胞滚动出来,并将其出列。 如果单元格缩小,找出哪些单元格滚动查看结果。

这是一个非常复杂的舞蹈。 你可以尝试在单元setNeedsLayout上调用setNeedsLayout ,但是我不希望这样做(即使是这样,它也是一个脆弱的方法)。 表视图负责pipe理它的单元格,所以如果你真的应该更新模型并重新加载一个单元格。

改变高度

所以基本上有两种方法:

第一个是实际重新加载单元格(而不是tableview)。 重新加载将调用新的heightForRow(不要忘记清除caching,如果你正在caching大小),这将返回适当的新的高度:

  let indexPaths = [NSIndexPath(forRow: ~the rows in question~, inSection: 0)] self.table.reloadRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic) 

(注意,这通常涉及重新加载多行;特别是如果您select/取消select,您必须重新加载更改的所有行。

但是,如果您只想更改单元格的大小和内容本身,并没有真正改变数据内容…例如:

  • 你点击了一些button,并在单元格中给出了新的本地文本(可能是一个帮助文本):

  • 你只改变了单元格的布局。 例如,您创build了一个更大的字体,或者更改了文本块的边距,以便更改文本块的高度,从而确实更改了整个单元格的高度:

在这种情况下,而不是重新加载,只是调用以下,这迫使tableview基本上做所有的animation,为此,它需要新的高度,所以它要求:

  self.table.beginUpdates() self.table.endUpdates() 

真正的解决scheme

我明白你的问题是什么 你正试图改变实际单元格的高度 – 但是你不会成功 – >而你不应该这样做。 看,细胞是观点,观点不应该有任何关于其数据的想法 – 观点是什么呈现。 如果你需要改变,你应该通知你的控制器这样做。 要做到这一点,你可以使用通知,但最好是协议/委托。

所以起初你在你的单元中创build一个协议,用来通知控制器有一个改变:

  protocol MyCellDelegate { func buttonTappedForCell(cell : UITableViewCell) } 

现在,您需要在包含表的视图控制器中遵循该协议:

  class MyClassWithTableView : MyCellDelegate 

最后,你需要在单元格中声明委托:

  class MyCell { var delegate : MyCellDelegate } 

并将其分配到您可能在视图控制器中的单元的configuration中:

  cell.delegate = self 

这实际上是所有代表/协议的基本设置,现在,当您单击button时,可以将操作转发给控制器:

  @IBAction myButtonTouchUpInside() { self.delegate.buttonTappedForCell(self) } 

完成所有这些之后,按照第1部分进行操作。也就是说,要么像上面解释的那样reloadRowsAtIndexPathsbeginUpdates / endUpdates对。

希望能帮助到你!

你尝试调用单元格索引reloadRowsAtIndexPaths? 它应该animation到新的大小,如果约束正确设置。

你应该调用self.tableView.reloadData() 之后,你做了单元格的标签的文本更改。

它将强制tableView重绘单元格。 当你滚动的时候就是这样,单元格正在被reused ,当它再次出现时重绘。

编辑:

如果你不能或者不会在你的tableView上做一个reloadData,你可以使用:

 self.tableView.beginUpdates() self.tableView.reloadRowsAtIndexPaths([NSIndexPath(row:0 section:0)] withRowAnimation:UITableViewRowAnimation.Automatic) self.tableView.endUpdates() 

我不知道你的代码,但你真的在主线程上执行你的UI更改。 同样的问题发生在我身上,解决了把主语放在主线上。

 dispatch_async(dispatch_get_main_queue()) { () -> Void in [...] }