如何在不滚动表的情况下将行插入UITableView的顶部? [英] How to insert rows to the top of UITableView without scrolling the table?

查看:202
本文介绍了如何在不滚动表的情况下将行插入UITableView的顶部?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在不滚动表格的情况下将行插入UITableView的顶部?同样的,当你拖动重新加载Twitter上的新推文或whatsApp中的消息

How to insert rows to the top of UITableView without scrolling the table? The same like when when you drag to reload new tweets on twitter or messages in whatsApp

我尝试做另一部分begin / endUpdate,要求它滚动到第三个索引,但它不起作用。它总是滚动到tableView的顶部。我希望它保持与添加新行之前的位置相同。

I tried doing another section of begin/endUpdate asking it to scroll to the 3rd index, but it didn't work. It always scrolls to the top of the tableView. I want it to stay at the same position as it was before adding the new rows.

    self.tableView.beginUpdates()
    let indexPath = IndexPath(row: 3, section: 0)
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
    self.tableView.endUpdates()

PS这是我真实项目中的一个示例项目,单元格的大小根据邮件大小而变化。

P.S. this is a sample project in my real project the cells varies in size based on the message size.

这是项目的链接:
https://github.com/akawther/TableView

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!
var loadMore: UIRefreshControl!

var labels = ["A","B","C","D","E","F","G","H","I","J","K"]

override func viewDidLoad() {
    super.viewDidLoad()

    self.loadMore = UIRefreshControl()
    self.loadMore.attributedTitle = NSAttributedString(string: "Pull to reload more")
    self.loadMore.addTarget(self, action: #selector(ViewController.loadMoreChats), for: .valueChanged)
    self.tableView.addSubview(self.loadMore)

    // Do any additional setup after loading the view, typically from a nib.
}

func loadMoreChats() {
    DispatchQueue.main.async(execute: {() -> Void in
        self.tableView.beginUpdates()
        self.labels.insert("3", at: 0)
        self.labels.insert("2", at: 0)
        self.labels.insert("1", at: 0)
        let indexPaths = [
            IndexPath(row: 0, section: 0),
            IndexPath(row: 1, section: 0),
            IndexPath(row: 2, section: 0),
        ]
        self.tableView.insertRows(at: indexPaths, with: .top)
        self.tableView.endUpdates()
        self.loadMore.endRefreshing()

        self.tableView.beginUpdates()
        let indexPath = IndexPath(row: 3, section: 0)
        self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
        self.tableView.endUpdates()
    })
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return labels.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! customCellTableViewCell

    cell.label.text = labels[indexPath.row]
    return cell
}

}

UPDATE#1:
我刚刚尝试了我的第二次更新/结束更新CATransaction,但仍显示顶部是1而不是我想要的A:

UPDATE #1: I have just tried it also by surrounding my second being/end update with CATransaction, but still the top displayed is 1 instead of A like I want:

        CATransaction.begin()
        self.tableView.beginUpdates()
        CATransaction.setCompletionBlock { () -> Void in
            let indexPath = IndexPath(row: 3, section: 0)
            self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
        }
        self.tableView.endUpdates()
        CATransaction.commit()

UPDATE #2:
使用@beyowulf的答案更新github项目

UPDATE #2: The github project is updated with the answer from @beyowulf

推荐答案

此代码有效当 loadMoreChats 是按钮的目标时,我很好:

This code worked fine for me when loadMoreChats was a target of a button:

    func loadMoreChats() {
        self.loadMore.endRefreshing()

        self.labels.insert("3", at: 0)
        self.labels.insert("2", at: 0)
        self.labels.insert("1", at: 0)

        self.tableView.reloadData()
        let indexPath = IndexPath(row: 3, section: 0)
        self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
    }

使用刷新控制案例 scrollToRow 被触发它的平移手势覆盖。

Using a refresh control cases the scrollToRow to be overridden by the pan gesture that triggered it.

请注意,您引用的应用程序不会以这种方式使用刷新控制器,但是如果您坚持使用一个我认为您可以在编程方式滚动表视图时暂时禁用平移手势。类似于:

Note that the apps that you reference don't use a refresh controller in this way, but if you insist on using one I supposed you could disable the pan gesture briefly while you programmatically scroll the table view. Something like:

func loadMoreChats() {
    self.loadMore.endRefreshing()

    self.labels.insert("3", at: 0)
    self.labels.insert("2", at: 0)
    self.labels.insert("1", at: 0)

    self.tableView.reloadData()
    let indexPath = IndexPath(row: 3, section: 0)
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)

    self.tableView.panGestureRecognizer.isEnabled = false
    let when = DispatchTime.now() + 0.05
    DispatchQueue.main.asyncAfter(deadline: when)
    {
        self.tableView.panGestureRecognizer.isEnabled = true
    }
}

我发现这相当hacky并建议反对它。

I find this to be rather hacky and would recommend against it.

这篇关于如何在不滚动表的情况下将行插入UITableView的顶部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆