Ios 不断更新单元格大小时滚动到顶部的问题
我有一个带有自动调整单元格大小的UITableView。每个单元格的内容都围绕着时间计数,因此单元格的大小每秒都可能发生变化。我目前正在使用一个每1秒计划一次的计时器来告诉表视图更新单元格大小: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
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,则会自动解析单元格大小,后续的文本更改不会触发它,因此不会更新大小。您可以提供用于滚动到列表顶部的代码吗?