【问题标题】:Prevent UITableView from scrolling when new cells are inserted插入新单元格时防止 UITableView 滚动
【发布时间】:2018-06-16 03:28:27
【问题描述】:

我已经多次看到这个问题被问到,尽管我已经实施了社区提出的每个解决方案,但我仍然没有成功。我正在实施的是一个基本的公共聊天应用程序。我需要在 UITableView 中显示通过我的 API 收到的许多消息。为了有一种聊天的感觉,我通过将 UITableView 和 UITableViewCell 的 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 的底部时,一切都很好:新的单元格从下到上出现,伴随着流畅的动画。当我滚动到顶部几个像素时,问题就开始了。查看这些图片以更好地了解其中的区别。

我想要实现的是防止 UITableView 滚动,除非我在它的最底部,这样,如果用户滚动到顶部以阅读过去的消息,他可以这样做而不会引起任何麻烦UITableView 的移动。

我希望有人能指出我正确的方向。谢谢

编辑:如果有帮助,我正在使用自动 UITableViewCell 高度。

编辑:这是我当前的代码:

我正在使用通用包装器class ListView<Cell: UITableViewCell, Item>,此方法用于添加新项目:

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的内容偏移量,插入后重新应用?
  • 当然。它没有用。也许与一切都颠倒的事实有关?

标签: ios swift uitableview cocoa-touch uiscrollview


【解决方案1】:
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 &gt; -contentInset.top { reloadData() } else { insertRows(at: [indexPath], with: animation) } CGAffineTransform(scaleX: 1, y: -1) 是一个将 UITableView 倒置的小技巧
  • 这看起来不错。但是我认为当您使用CGAffineTransform(scaleX: 1, y: -1) 转换视图时,您的tableView 无法正确更新它的contentOffset,这会导致此问题。我已经更新了我的答案。请看一下。我希望它能解决你的问题。
  • 我已经尝试过您的代码,并且......它有效!我永远不会再更改转换属性 :D 谢谢谢谢谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多