iOS8更改dynamic单元格的高度“现在”,重新设置内部单元格内容
这是一个dynamic的单元格
注意 – 在这个例子中,文本不是数据驱动的。 这只是一些本地的单元格文本(例如,帮助文本)。 在运行时,使用单元格内的button,将UILabel的.text从一个单词改为多行。 iOS正确调整单元格和表的大小…
…但只有当单元格在屏幕外滚动,然后再次打开 。
如何提醒表视图重新计算“现在”的一切?
(请注意,这个问题只适用于dynamic单元格高度的iOS8 +,Xcode7 +自动布局。)
我假设你不是在cellForRowAtIndexPath
设置UILabel
的text
属性,而是在其他地方(或者是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部分进行操作。也就是说,要么像上面解释的那样reloadRowsAtIndexPaths
或beginUpdates
/ 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 [...] }