swift ios 向 uitableview 添加无限滚动分页

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39215081/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 10:00:34  来源:igfitidea点击:

swift ios add infinite scroll pagination to uitableview

iosswiftuitableviewinfinite-scroll

提问by user2636197

I wonder if tableview has any built-in function to add infinite scroll/pagination.

我想知道 tableview 是否有任何内置函数来添加无限滚动/分页。

Right now my VC looks like this:

现在我的 VC 看起来像这样:

var data: JSON! = []

override func viewDidLoad() {
    super.viewDidLoad()

    //Init start height of cell
    self.tableView.estimatedRowHeight = 122
    self.tableView.rowHeight = UITableViewAutomaticDimension

    self.tableView.delegate = self
    self.tableView.dataSource = self

    savedLoader.startAnimation()
    //Load first page
    loadSaved(1)

}

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

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("aCell") as! SavedTableViewCell

    let info = data[indexPath.row]
    cell.configureWithData(info)

    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    performSegueWithIdentifier("WebSegue", sender: indexPath)

    tableView.deselectRowAtIndexPath(indexPath, animated: false)
}

I fetch my data using loadSaved(1)by giving the function the current page I want to load. The function makes a API request using alomofire then populate the var data: JSON! = []with the data that should be displayed

我使用loadSaved(1)通过为函数提供我想要加载的当前页面来获取我的数据。该函数使用 alomofire 发出 API 请求,然后填充var 数据:JSON!= []带有应显示的数据

So what I want to do is when I scroll to the bottom of the tableview loadSaved(2)should be called loading more data into the tableview

所以我想要做的是当我滚动到 tableview 的底部时loadSaved(2)应该被称为将更多数据加载到 tableview

回答by lukkea

The UITableViewDelegate has a table?View(_:?will?Display:?for?Row?At:?) instance methodwhich "tells the delegate the table view is about to draw a cell for a particular row."

UITableViewDelegate 有一个table?View(_:?will?Display:?for?Row?At:?) 实例方法,它“告诉委托表视图即将为特定行绘制一个单元格。”

In your case I would use it something like this:

在你的情况下,我会像这样使用它:

override open func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if indexPath.row == data.count-1 { //you might decide to load sooner than -1 I guess...
      //load more into data here
    }
}

Depending on your code, you may need some checks around this to ensure you don't end up in an infinite loop if you've loaded all your data...

根据您的代码,您可能需要对此进行一些检查,以确保在您加载了所有数据后不会陷入无限循环......

回答by Victor Sigler

No, the UITableViewhas not any built-in function to achieve the infinite scroll or load on-demandcells like you want. What you can use is the function scrollViewDidScroll(_:)in the UIScrollViewDelegateimplemented by default in the UITableViewand in this way know when the user scroll more than the original height defined in the UITableView.

不,UITableView它没有任何内置功能来实现您想要的无限滚动或按需加载单元格。您可以使用的是默认实现的功能scrollViewDidScroll(_:),并UIScrollViewDelegate通过UITableView这种方式知道用户何时滚动超过UITableView.

For example like in this code:

例如像在这段代码中:

var indexOfPageToRequest = 1

override func scrollViewDidScroll(scrollView: UIScrollView) {

    // calculates where the user is in the y-axis
    let offsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height

    if offsetY > contentHeight - scrollView.frame.size.height {

        // increments the number of the page to request
        indexOfPageToRequest += 1

        // call your API for more data
        loadSaved(indexOfPageToRequest)

        // tell the table view to reload with the new data
        self.tableView.reloadData()
    }
}

To achieve the result of add the rest of the elements at the end of the UITableViewyou should add the new elements to the data source, in your case datainside your function loadSaved(numberOfPage).

要实现在末尾添加其余元素的结果,UITableView您应该将新元素添加到数据源中,在您的情况下是data在您的函数中loadSaved(numberOfPage)

I hope this help you.

我希望这对你有帮助。

回答by Ravi_sankar

I have modified Victor's answer and used it as ,

我修改了维克多的答案并将其用作,

var indexOfPageRequest = 1
var loadingStatus = false

func loadData(){
    if !loadingStatus{
        loadingStatus = true
        viewModel.getData(pageIndex: indexOfPageRequest)
    }
}

override func scrollViewDidScroll(_ scrollView: UIScrollView) {

    // calculates where the user is in the y-axis
    let offsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height

    if offsetY > contentHeight - scrollView.frame.size.height {

        // increments the number of the page to request
        indexOfPageRequest += 1

        // call your API for more data
        loadData()

        // tell the table view to reload with the new data
        self.tableView.reloadData()
    }
}

Reset loadingStatus to true when you receive data. Without checking if the view was already loading more data, the tableview was flickering.

接收数据时将 loadingStatus 重置为 true。没有检查视图是否已经加载了更多数据,tableview 正在闪烁。

回答by amar

All the above answers are correct but for iOS 10 and above we have a very nice

以上所有答案都是正确的,但对于 iOS 10 及更高版本,我们有一个非常好的

func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])

This is a prefetch delegate which needs to be set

这是一个需要设置的预取委托

tableView.prefetchDataSource = self

RayWeinderlichhas a nice tutorial on the topic. Since Rays is a dependable site i am not posting code here

RayWeinderlich有一个关于这个主题的不错的教程。由于 Rays 是一个可靠的网站,我不会在这里发布代码

回答by iPhoneDeveloper

Ravi's answer looks good. But as he pointed out in the end, the tableView flickersa lot if you use scrollViewDidScroll(_ scrollView: UIScrollView)

拉维的回答看起来不错。但正如他最后指出的那样,如果您使用,tableView 会闪烁很多scrollViewDidScroll(_ scrollView: UIScrollView)

This is because you are trying to reload tableView every time you are scrolling the tableView.

这是因为您每次滚动 tableView 时都试图重新加载 tableView。

Instead you could use scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)delegate method to determine whether you have scrolled enough and have reached almost the end of the tableView.

相反,您可以使用 scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)委托方法来确定您是否已经足够滚动并几乎到达 tableView 的末尾。

override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    let offsetY = scrollView.contentOffset.y
        let contentHeight = scrollView.contentSize.height

        if offsetY > contentHeight - scrollView.frame.size.height {
               indexOfPageRequest += 1
               loadData()
               self.tableView.reloadData()
        }

    }

回答by Kraming

There are number of ways we can do this. The essense of all different ways, is to load next set of data when user scroll to last. I have implemented it via adding an extra special cell at the end of tableView and when that cell gets loaded in willDisplay cell: forRowAtIndexPath:which triggers next set of fetching of data.

我们有很多方法可以做到这一点。所有不同方式的本质是当用户滚动到最后一组时加载下一组数据。我已经通过在 tableView 的末尾添加一个额外的特殊单元格来实现它,并且当该单元格被加载时willDisplay cell: forRowAtIndexPath:会触发下一组数据获取。

Athough this is simple to implement but in larger apps at times we need to implement it many places. To avoid this, I wrote a small frameworkwhich is non-intrusive and can be easyly integrated.

虽然这很容易实现,但在较大的应用程序中,有时我们需要在很多地方实现它。为了避免这种情况,我编写了一个非侵入性且易于集成的小框架

回答by Vishal Wagh

Above Ans are also right, but may be some one help out this code also.

上面的 Ans 也是对的,但也可能有人帮助解决此代码。

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath){
    if(indexPath.row == self.arryOfData.count-1){
        if(self.pageNumber <= self.resPgNumber){
            if(remaining != 0){
                let spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
                spinner.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(44))
                spinner.startAnimating()
                tableView.tableFooterView = spinner
                tableView.tableFooterView?.isHidden = false

                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    self.flgActivity = false
                    self.getActiveOrdersList()
                }
            }
            else{
                tableView.tableFooterView?.removeFromSuperview()
                let view = UIView()
                view.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(5))
                tableView.tableFooterView = view
                tableView.tableFooterView?.isHidden = true
            }
        }
        else{
            tableView.tableFooterView?.removeFromSuperview()
            let view = UIView()
            view.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(5))
            tableView.tableFooterView = view
            tableView.tableFooterView?.isHidden = true
        }
    }
    else{
        tableView.tableFooterView?.removeFromSuperview()
        let view = UIView()
        view.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(5))
        tableView.tableFooterView = view
        tableView.tableFooterView?.isHidden = true
    }
}