iOS8“现在”改变动态单元格的高度,重新内部单元格内容

Posted

技术标签:

【中文标题】iOS8“现在”改变动态单元格的高度,重新内部单元格内容【英文标题】:iOS8 change height of dynamic cell "now", re internal cell content 【发布时间】:2015-09-19 21:48:10 【问题描述】:

这是一个动态单元格

注意 - 在示例中,文本不是数据驱动的。它只是单元格本地的一些文本(例如,考虑帮助文本)。在运行时,使用单元格内的按钮将 UILabel 的 .text 从一个单词更改为多行。 ios 完美调整单元格和表格的大小....

...但仅当单元格滚动到屏幕外,然后再次打开时

如何提醒表格视图“现在”重新计算所有内容?


(请注意,此问题仅适用于 iOS8+、Xcode7+、动态单元格高度的自动布局。)

【问题讨论】:

emm,我想你应该在为标签分配新文本时以某种方式触发自动布局,并且内部魔法确实休息了。还是有什么不那么直截了当的? 我添加了解释为什么您不应该 - 永远 - 更改单元格中的内容,并添加了有关如何执行此操作的解决方案。 【参考方案1】:

改变高度

所以基本上,有两种方法可以做到:

第一个是实际重新加载单元格(不是表格视图)。重新加载将调用新的 heightForRow(如果您正在缓存大小,请不要忘记清除缓存),这将返回正确的新高度:

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

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

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

您单击了某个按钮并将单元格中的新本地文本分配给了插座(可能是帮助文本):

您只更改了单元格的布局。例如,您将字体变大,或者更改了文本块的边距,从而使文本块的高度发生了变化,因此整个单元格的高度确实发生了变化:

在这种情况下,而不是重新加载,只需调用以下命令,这会强制 tableview 基本上执行所有动画,为此它需要新的高度,所以它请求它:

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

真正的解决方案

我明白你的问题是什么。您正在尝试从实际单元格更改单元格的高度 - 但您不会成功 -> 而且您不应该这样做。看,单元格是视图,视图不应该对它的数据有任何想法——视图就是呈现的东西。如果您需要任何更改,您应该通知您的控制器这样做。为此,您可以使用通知,但最好使用协议/委托。

因此,首先您在单元格中创建协议,该协议将用于通知控制器存在更改:

 protocol MyCellDelegate 

    func buttonTappedForCell(cell : UITableViewCell)
 

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

 class MyClassWithTableView : MyCellDelegate

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

 class MyCell 
     var delegate : MyCellDelegate
 

并在单元格的配置中分配它,您可能在视图控制器中拥有它:

 cell.delegate = self

这是所有委托/协议的基本设置,现在,当您单击按钮时,您可以将操作转发给您的控制器:

 @IBAction myButtonTouchUpInside() 

     self.delegate.buttonTappedForCell(self)
 

完成所有这些后,按照第 1 部分进行操作。也就是说,reloadRowsAtIndexPathsbeginUpdates / endUpdates 对,如上所述。

希望对你有帮助!

【讨论】:

我为你的其他问题添加了解决方案,因为我终于明白了你真正想要做什么:) 嗨,吉里!我意识到您对reloadRowsAtIndexPathsbeginUpdates / endUpdates 对之间的区别的解释是至关重要的。实际上,我继续大胆地编辑了您的答案以扩展这一点。看看你喜不喜欢.... 顺便说一句,我刚刚发现 setNeedsUpdateConstraints 。 . .有趣的是,没有人在这种情况下提到它。它的作用类似于'reloadRowsAtIndexPaths 这就是为什么它不应该这样 :) ***.com/questions/20609206/… Jiri,感谢您提供大量有用的信息,我相信这些信息对未来的谷歌用户也将非常有用。我点击了一个象征性的赏金以表示感谢,谢谢!【参考方案2】:

我假设您没有在cellForRowAtIndexPath 内设置UILabeltext 属性,而是在其他地方设置(或异步执行)。如果是这种情况,我不会在那里更新 UI。相反,我会更新支持表格的模型,然后调用reloadRowsAtIndexPaths。这将使cellForRowAtIndexPath 再次调用,但与重新加载整个表格不同,这将优雅地保持表格视图的contentOffset 正确。

我知道这一切听起来都不必要地复杂,但底线是您不拥有该视图,而表格视图拥有。除了更新单元格之外,它还必须做各种事情。即,如果单元格增长,找出哪些单元格滚动出视图并将它们出列。如果单元格缩小,请找出哪些单元格因此滚动到视图中。

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

【讨论】:

明白了,这很有意义。你只是不能让细胞对自己做任何事情,真的。毕竟它是一个实体,可能在屏幕上也可能不在屏幕上,可以从原型中随时形成或重新形成等等。(重新设置NeedsLayout,它似乎什么都不做!) 全面披露,有时人们会直接异步更新单元格。 (最常见的示例包括所有用于异步图像加载的各种UIImageView 类别。)但这些仅在单元格高度不变的情况下才有效。在架构上,这是错误的方法。最好更新模型,然后调用reloadRowsAtIndexPaths【参考方案3】:

您是否尝试在单元格索引上调用 reloadRowsAtIndexPaths?如果约束设置正确,它应该动画到新的大小。

【讨论】:

【参考方案4】:

您应该在更改单元格标签的文本之后致电self.tableView.reloadData()

它将强制tableView 重绘单元格。这就是你滚动时发生的情况,单元格是reused,当它再次返回时会重新绘制。

编辑:

如果您不能或不会在您的 tableView 上执行 reloadData,您可以使用:

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

【讨论】:

其实如果你的内容是静态的并且是那种“帮助”的形式,一个简单的 reloadData() 会很快的 @JoeBlow 一点也不,reloadRowsAtIndexPaths 只会重新加载您提供的行数组。如果您提供一个只有一行的数组,它将只重新加载这一行。没有其他方法可以提高效率 顺便说一句,beingUpdatesendUpdates 仅在您要一起执行多个更新时才需要。如果是单个reloadRowsAtIndexPaths,则不需要begin/endUpdates 但是@Rob我意识到,如果我没记错的话,如果你只是改变了布局,你确实可以调用beginUpdates / endUpdates 对(假设将点大小增加三倍)文本中的字体,因此单元格现在要长得多)。相反,如果(正如我的问题所问的那样)您实际上是在更改模型数据(我们现在知道,应该),那么确实必须重新加载。我认为听起来不错........(我希望:)) @JoeBlow - 是的,正如文档所说“您还可以使用 [beginUpdates] 后跟 endUpdates 方法来动画行高的变化,而无需重新加载单元格。”但是调用beginUpdates,然后重新加载一个单元格,然后调用endUpdates是多余的。【参考方案5】:

我不知道你的代码,但你真的在主线程上执行了你的 ui 更改吗?同样的问题也发生在我身上,通过将执行放在主线程上解决了。

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

【讨论】:

嗨 Philipp,这是一个很好的观点,但恐怕不是我的特殊问题!

以上是关于iOS8“现在”改变动态单元格的高度,重新内部单元格内容的主要内容,如果未能解决你的问题,请参考以下文章

具有自动布局的自定义单元格的动态高度

基于动态标签高度的 iOS8 动态单元格高度

内部另一个表视图的表视图行高

设置表格视图单元格的动态高度

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

动态更改表格视图单元格的高度