Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 不断更新单元格大小时滚动到顶部的问题_Ios_Swift_Uitableview - Fatal编程技术网

Ios 不断更新单元格大小时滚动到顶部的问题

Ios 不断更新单元格大小时滚动到顶部的问题,ios,swift,uitableview,Ios,Swift,Uitableview,我有一个带有自动调整单元格大小的UITableView。每个单元格的内容都围绕着时间计数,因此单元格的大小每秒都可能发生变化。我目前正在使用一个每1秒计划一次的计时器来告诉表视图更新单元格大小: Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timeUpdateNotification), userInfo: nil, repeats: true) @objc func timeUpdateN

我有一个带有自动调整单元格大小的UITableView。每个单元格的内容都围绕着时间计数,因此单元格的大小每秒都可能发生变化。我目前正在使用一个每1秒计划一次的计时器来告诉表视图更新单元格大小:

Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timeUpdateNotification), userInfo: nil, repeats: true)

@objc func timeUpdateNotification() {
    // ... cells get notified to update contents here ...

    tableView.beginUpdates()
    tableView.endUpdates()
}

这工作得相当好,但当用户点击滚动到列表顶部时会出现问题。这部动画有点僵硬,而且常常无法达到最佳效果。是否有更好的方法来处理此问题?

当他们单击滚动到顶部时,请使计时器无效,然后在计时器到达顶部时再次启动计时器

编辑:这样,它就不会更新内容,如果不更新表视图的“顶部”,内容可能会移动得更高。

我也遇到了类似的问题。 我通过手动计算每个单元的高度来解决这个问题

var cellHeights: [Int: CGFloat] = [:]
在cellForRowAtIndexPath方法中,计算高度:

cellHeights[byRow] = cell.getCellHeight()
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return presenter.cellHeights[indexPath.row] ?? 0
}
在细胞内

func getCellHeight() -> CGFloat {

    let userInfoHeight: CGFloat = userInfoHeightConstraint.constant
    let actionHeight: CGFloat = actionViewHeightConstraint.constant
    let descriptionBottom: CGFloat = descriptionBottomConstraint.constant

    let descriptionWidth = self.frame.width - leftAvatarConstraint.constant - descriptionRightConstraint.constant
    let descriptionHeight: CGFloat = descriptionLabel.textHeight(width: descriptionWidth)

    let height = userInfoHeight + actionHeight + descriptionBottom + descriptionHeight

    return height
}

extension UILabel {
func textHeight(width: CGFloat) -> CGFloat {

    var textHeight: CGFloat = 0

    if let text = self.text {

        let customLabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude))
        customLabel.numberOfLines = self.numberOfLines
        customLabel.text = text
        customLabel.font = self.font
        customLabel.sizeToFit()

        textHeight = customLabel.frame.height
    }

    return textHeight
}}
我正在使用UITableViewAutomaticDimension。 此外,我还可以在单击时更改单元格的大小

因此,在我的任务中,这很好:

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return presenter.cellHeights[indexPath.row] ?? 0
}
但我认为你可以立即设置高度:

cellHeights[byRow] = cell.getCellHeight()
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return presenter.cellHeights[indexPath.row] ?? 0
}

如果您在表格滚动时设置了一个标志,您可以在计时器功能中检测到它,并且在设置时不会更新
UITableView
UIScrollView
的后代,因此可以使用一些滚动视图委托来执行此操作。如果覆盖
scrollViewShouldScrollToTop()
scrollViewDidScrollToTop()
您将知道滚动视图何时滚动到顶部以及何时完成

override func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
    NSLog("scrollViewShouldScrollToTop")
    isScrolling = true
    return true
}

override func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
    NSLog("scrollViewDidScrollToTop")
    isScrolling = false
}
您还可以扩展此功能,以检测用户何时拖动/滚动视图,以防止计时器功能在这些情况下更新

override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    NSLog("scrollViewWillBeginDragging")
    isScrolling = true
}

override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if (!decelerate) {
        // Only catch if scrolling stopped
        NSLog("scrollViewDidEndDragging")
        isScrolling = false
    }
}
override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    NSLog("scrollViewDidEndDecelerating")
    isScrolling = false
}

我在函数中添加了一些日志记录,这样您就可以看到发生了什么。当然,您可以删除它们。

为什么不考虑在滚动期间禁用动画?我不确定这是否有帮助。在tableView更新开始之后,但在更新完成之前,可能会滚动或点击状态栏进入顶部。为什么需要手动更新单元格大小?在更改
cellForRowAtIndexPath
方法中的单元格内容后,
UITableView
将通过调用
HeightForRowAtexPath
来解析单元格大小,或者如果您使用的是
AutoLayout
EstimatedRow
仅在初始布局时调用cellForRow,则会自动解析单元格大小,后续的文本更改不会触发它,因此不会更新大小。您可以提供用于滚动到列表顶部的代码吗?