首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用文本视图更新自调整表视图单元格的高度

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

Stack Overflow用户
提问于 2016-02-07 21:24:41
回答 3查看 4.5K关注 0票数 6

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

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

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

EN

回答 3

Stack Overflow用户

发布于 2016-02-10 17:12:12

节流溶液

reloadRowsAtIndexPaths的问题是,UITextFieldresignFirstResponder,因为从本质上讲,单元是重新加载的:即销毁。

相反,beginUpdates() & endUpdates()确实维护现有的单元格,但是在包含scrollEnabled UITextView的单元格上调用时会感到不安,如果每个textViewDidChange都被触发。

限制更新频率

此解决方案基于流行的textViewDidChange方法,仅通过推迟更新来减少或停止闪烁。

UITableViewCell**:** 子类

代码语言:javascript
运行
复制
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()
            }
        }
    }
}

脱队列&更新闭包:

代码语言:javascript
运行
复制
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上的►找到了这个解决方案,还有关于斯威夫特的其他详细信息。

票数 3
EN

Stack Overflow用户

发布于 2018-01-28 07:29:26

如果在调用beginUpdates之前禁用UIView动画,则该方法可以工作。

代码语言:javascript
运行
复制
//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()
}
票数 3
EN

Stack Overflow用户

发布于 2016-02-07 21:47:31

不能更改现有UITableViewCell的高度。您要告诉UITableView单元格无效,然后重新加载它。

在重新加载单元格(cellForRowAtIndexPath)时,您可以传递新的更新的单元格。使用tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)触发单个单元格刷新。

reloadRowsAtIndexPaths并没有reloadData()那么激烈。这是一个准时的索引刷新,不需要被tableView.beginUpdatestableView.endUpdates包围,您可以提供自己选择的动画方法,比如.Fade

参见reloadRowsAtIndexPaths(_:withRowAnimation:)中的文档

还可以访问这个堆栈溢出回答,它详细描述了更改单元格高度的情况。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35259289

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档