繁体   English   中英

使用文本视图更新自调整大小的表格视图单元格的高度

[英]Updating the Height of a Self-Sizing Table View Cell with a Text View

我有一个类似于 Mail 中的 Compose 屏幕的表格视图,其中一个单元格用于文本输入。 我希望通过使用自动布局将单元格的contentView约束到其UITextView子视图来自动调整单元格的大小。 表格视图的rowHeightestimatedRowHeight设置为UITableViewAutomaticDimension 此外,文本视图的scrollEnabled属性设置为false ,以便它报告它的intrinsicContentSize

但是,当用户输入文本行时,单元格不会更新其高度,即使文本视图本身确实会更新其内在内容大小。 据我所知,手动请求此请求的唯一方法是让表视图调用beginUpdates()endUpdates() 然后单元格的高度会正确更新,但这也会导致整个表格视图的重新布局。 这是(其他人的) 演示问题的示例代码

如何在不布局整个表格视图的情况下反映单元格文本视图中的更改?

限制解决方案

reloadRowsAtIndexPaths的问题在于UITextFieldresignFirstResponder因为从本质上讲,单元格被重新加载: 即被破坏

相反地, 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秒,则不会进行更新。 这显着减少了闪烁。

帧延迟

LinkedIn重播动画


►在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.beginUpdatestableView.endUpdates包围,您可以提供您选择的动画方法,例如.Fade

reloadRowsAtIndexPaths(_:withRowAnimation:)的文档


另请参阅此Stack Overflow应答 ,其中详细介绍了更改单元格高度。

动画演示

我在网上搜索到了一些东西,我想和我们分享

https://levelup.gitconnected.com/beginner-ios-dev-embedded-uitextview-inside-a-uitableview-cell-56f59f3d0b45

谢谢 Jamas Tapping 的好教程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM