[英]Updating the Height of a Self-Sizing Table View Cell with a Text View
我有一个类似于 Mail 中的 Compose 屏幕的表格视图,其中一个单元格用于文本输入。 我希望通过使用自动布局将单元格的contentView
约束到其UITextView
子视图来自动调整单元格的大小。 表格视图的rowHeight
和estimatedRowHeight
设置为UITableViewAutomaticDimension
。 此外,文本视图的scrollEnabled
属性设置为false
,以便它报告它的intrinsicContentSize
。
但是,当用户输入文本行时,单元格不会更新其高度,即使文本视图本身确实会更新其内在内容大小。 据我所知,手动请求此请求的唯一方法是让表视图调用beginUpdates()
和endUpdates()
。 然后单元格的高度会正确更新,但这也会导致整个表格视图的重新布局。 这是(其他人的) 演示问题的示例代码。
如何在不布局整个表格视图的情况下反映单元格文本视图中的更改?
reloadRowsAtIndexPaths
的问题在于UITextField
将resignFirstResponder
因为从本质上讲,单元格被重新加载: 即被破坏 。
相反地, beginUpdates()
endUpdates()
上含有的细胞当被调用时都保持现有的细胞,但抖动scrollEnabled
UITextView
如果每单触发textViewDidChange
。
限制更新频率
此解决方案基于流行的textViewDidChange
方法,仅通过推迟更新来完全减少或停止闪烁。
子类UITableViewCell
:
class TableViewTextViewCell : UITableViewCell, UITextViewDelegate {
var refreshCell:(() -> Void)? = nil
var textViewDirtyCount = 0
// MARK: - UITextViewDelegate
func textViewDidChange(_ textView: UITextView) {
textViewDirtyCount += 1
perform(#selector(TableViewTextViewCell.queuedTextVewDidChange),
with: nil,
afterDelay: 0.3) // Wait until typing stopped
}
func textViewDidBeginEditing(_ textView: UITextView) {
textViewDirtyCount = 0 // initialize queuedTextVewDidChange
}
func textViewDidEndEditing(_ textView: UITextView) {
textViewDirtyCount = -1 // prevent any further queuedTextVewDidChange
}
func queuedTextVewDidChange() {
if textViewDirtyCount > 0 {
textViewDirtyCount -= 1
if 0 == textViewDirtyCount, let refreshCell = refreshCell {
refreshCell()
}
}
}
}
出队和更新关闭:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(
"cell", forIndexPath: indexPath) as! TableViewTextViewCell
cell.refreshCell = {
() -> Void in
tableView.beginUpdates()
tableView.endUpdates()
}
return cell
}
注意输入最后一个字符后的0.3秒延迟; 如果自上次更改后经过的时间少于0.3秒,则不会进行更新。 这显着减少了闪烁。
►在GitHub上找到此解决方案以及有关Swift Recipes的其他详细信息。
如果在调用之前禁用UIView动画,则beginUpdates方法有效。
//inside of cellForRowAtIndexPath
cell.performCellUpdates = { [unowned self] in
UIView.setAnimationsEnabled(false) //the secret sauce, prevents the jitter
self.tv.beginUpdates()
self.tv.endUpdates()
UIView.setAnimationsEnabled(true) //don't forget to turn animations back on
}
...
//inside of cell subclass
func textViewDidChange(_ textView: UITextView) {
textView.sizeToFit()
performCellUpdates()
}
将这个发布给像我这样晚会的其他人:)
您无法更改现有UITableViewCell
的高度。 您想告诉UITableView
该单元格无效,并重新加载它。
在重新加载单元格( cellForRowAtIndexPath
)时,您可以传递新的更新单元格。 并使用tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
触发单个单元格刷新
reloadRowsAtIndexPaths
并不像reloadData()
那样激烈。 这是一个准时的索引刷新,不需要被tableView.beginUpdates
和tableView.endUpdates
包围,您可以提供您选择的动画方法,例如.Fade
。
见reloadRowsAtIndexPaths(_:withRowAnimation:)
中的文档 。
另请参阅此Stack Overflow应答 ,其中详细介绍了更改单元格高度。
我在网上搜索到了一些东西,我想和我们分享
谢谢 Jamas Tapping 的好教程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.