防止 UITableView 在插入新单元格时滚动

4
我曾多次看到这个问题被问及,尽管我已经实现了社区提出的每个解决方案,但我仍然没有成功。我正在实现一个基本的公共聊天应用程序。我需要在UITableView中显示许多通过API接收到的消息。为了具有聊天感觉,我通过将它们的transform属性更改为CGAffineTransform(scaleX:1,y:-1)来颠倒UITableView和UITableViewCell。相反,要向UITableView添加单元格,我首先通过messages.insert(message, at:indexPath.row)将传入的消息添加到数组中,然后调用insertRows(at:[indexPath],with:animation)(其中indexPath是这样创建的IndexPath(row:0,section:0))。当我在UITableView底部时,一切都很好:新单元格从底部到顶部出现,并伴随着平滑的动画。当我向上滚动几个像素时,问题就开始了。查看这些图像以更好地理解差异。

enter image description hereenter image description here

我希望能够防止UITableView滚动,除非我在它的底部,以便用户可以顺利阅读以前的信息,而不会受到UITableView移动的干扰。我希望有人能指点我正确的方向。谢谢。
编辑:如果有帮助,我正在使用自动UITableViewCell高度。
编辑:这是我的当前代码:
我正在使用一个通用的包装器,其中使用此方法添加新项目:
func add(_ item: Item) {
    items.insert(item, at: 0)

    if contentOffset.y > -contentInset.top {
        insertRows(at: [IndexPath(row: 0, section: 0)], with: .top)
    } else {
        reloadData()
    }
}

为了检查是否到达滚动视图的底部,我不得不使用-contentInset.top,因为我之前为布局原因将contentInset设置为UIEdgeInsets(top: composeMessageView.frame.height - 4, left: 0, bottom: 4, right: 0)。同样,我将estimatedRowHeight设置为44,rowHeight设置为UITableViewAutomaticDimension。


你尝试过在插入新行之前保存tableview的内容偏移量,并在插入后重新应用它吗? - Puneet Sharma
当然。它没有起作用。也许与一切都颠倒有关? - lucamegh
2个回答

3
func add(_ item: Item) {
    // Calculate your `contentOffset` before adding new row
    let additionalHeight = tableView.contentSize.height - tableView.frame.size.height
    let yOffset = tableView.contentOffset.y

    // Update your contentInset to start tableView from bottom of page
    updateTableContentInset()

    items.append(item)       

    // Create indexPath and add new row at the end
    let indexPath = IndexPath(row: objects.count - 1, section: 0)
    tableView.insertRows(at: [indexPath], with: .top)

    // Scroll to new added row if you are viewing latest messages otherwise stay at where you are
    if yOffset >= additionalHeight {
        tableView.scrollToRow(at: indexPath, at: .top, animated: true)
    }
}

这里是更新 contentInset 的方法。它将给您与此 CGAffineTransform(scaleX: 1, y: -1) 实现的相同效果。
func updateTableContentInset() {
    var contentInsetTop = tableView.frame.size.height - tableView.contentSize.height
    if contentInsetTop <= 0 {
        contentInsetTop = 0
    }
    tableView.contentInset = UIEdgeInsets(top: contentInsetTop, left: 0, bottom: 0, right: 0)
}

区分这两种情况的想法很好,但是它并不能起作用。我已经将其更改为:if contentOffset.y > -contentInset.top { reloadData() } else { insertRows(at: [indexPath], with: animation) } CGAffineTransform(scaleX: 1, y: -1) 是一个小技巧,用于将UITableView上下翻转。 - lucamegh
这看起来很好。但是我认为当你使用CGAffineTransform(scaleX: 1, y: -1)转换你的视图时,你的tableView无法正确更新它的contentOffset,从而导致了这个问题。我已经更新了我的答案。请看一下。我希望它能解决你的问题。 - Umair Aamir
我已经尝试了你的代码,它很有效!我再也不会改变转换属性了 :D 谢谢谢谢谢谢 - lucamegh

0
我也遇到了这个问题——在插入或删除第一行时,内容偏移的转换不稳定(我的表视图没有倒置,但有一个大的静态表头组件)。
最后,我通过为第一行添加一个额外的空单元格(高度设置为1),解决了这个问题。现在,当我删除或插入第二行时,就不再出现任何故障,偏移量保持如预期。
(iOS 16.5和Xcode 14.2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接