繁体   English   中英

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

[英]swift ios add infinite scroll pagination to uitableview

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

现在我的 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)
}

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

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

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

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

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
    }
}

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

不, UITableView没有任何内置函数来实现无限滚动或按需加载单元格。 您可以使用的是UIScrollViewDelegate的函数scrollViewDidScroll(_:)UITableView默认实现,这样就知道用户何时滚动超过UITableView定义的原始高度。

例如像在这段代码中:

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()
    }
}

为了实现在结尾处添加元素的其余部分的结果UITableView你应该添加新的元素到数据源,在你的情况下data的函数中loadSaved(numberOfPage)

我希望这对你有帮助。

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

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

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

tableView.prefetchDataSource = self

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

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

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()
    }
}

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

首先,创建一个带有Xib文件的UITableViewCell并在单元格的中心添加一个UIActivityIndicatorView

然后, Control+left click并将UIActivityIndicatorView拖到您的 .swift 文件中,并命名为activityIndicator ……并添加“ loadingcellid ”作为Identifier

现在,让我们进入我们有UITableView TableViewController ,并在viewDidLoad()注册加载单元。

override func viewDidLoad() {
    super.viewDidLoad()
    //...
    
    //Register Loading Cell
    let tableViewLoadingCellNib = UINib(nibName: "LoadingCell", bundle: nil)
    self.tableView.register(tableViewLoadingCellNib, forCellReuseIdentifier: "tableviewloadingcellid")
}

UITableView's委托和数据源中,我们在numberOfRowsInSection方法中添加以下代码。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0 {
        //Return the amount of items
        return itemsArray.count
    } else if section == 1 {
        //Return the Loading cell
        return 1
    } else {
        //Return nothing
        return 0
    }
}

..我们返回 2 个部分(一个用于项目,一个用于Loading Cell )。

  func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

cellForRowAt方法中,我们返回每个部分的单元格:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "tableviewitemcellid", for: indexPath) as! TableViewItemCell
            cell.itemLabel.text = itemsArray[indexPath.row]
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: 
       "tableviewloadingcellid", for: indexPath) as! TableViewLoadingCell
            cell.activityIndicator.startAnimating()
            return cell
        }
    }

...我们还设置了行height

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath.section == 0 {
        return 44 //Item Cell height
    } else {
        return 55 //Loading Cell height
    }
}

接下来,我们使用方法scrollViewDidScroll ,来自UITableView嵌入的UIScrollView ,来检测用户何时接近列表末尾以调用该方法......

 var isLoading = false

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = scrollView.contentOffset.y
        let contentHeight = scrollView.contentSize.height

        if (offsetY > contentHeight - scrollView.frame.height * 4) && !isLoading {
            loadMoreData()
        }
    }

... loadMoreData() 下载更多数据。

func loadMoreData() {
    if !self.isLoading {
        self.isLoading = true
        DispatchQueue.global().async {
            // Fake background loading task for 2 seconds
            sleep(2)
            // Download more data here
            DispatchQueue.main.async {
                self.tableView.reloadData()
                self.isLoading = false
            }
        }
    }
}

它运行良好,形成更多:- https://johncodeos.com/how-to-add-load-more-infinite-scrolling-in-ios-using-swift/

在此处输入图片说明

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

这是因为您每次滚动 tableView 时都试图重新加载 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()
        }

    }

上面的 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
    }
}

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM