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

时间:2016-08-29 20:57:17

标签: ios swift uitableview infinite-scroll

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

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

我使用 loadSaved(1)获取数据,方法是为我要加载的当前页面提供功能。该函数使用alomofire发出API请求,然后填充 var data:JSON! = [] 包含应显示的数据

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

8 个答案:

答案 0 :(得分:22)

UITableViewDelegate有一个table​View(_:​will​Display:​for​Row​At:​) instance method,它“告诉委托表视图即将绘制特定行的单元格。”

在你的情况下,我会用这样的东西:

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

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

答案 1 :(得分:4)

不,UITableView没有任何内置函数来实现无限滚动或按需添加按需单元格。您可以使用UIScrollViewDelegate中的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() } } 中实现,并以这种方式知道用户何时滚动超过{{1}中定义的原始高度}。

例如,在此代码中:

UITableView

要实现在data末尾添加其余元素的结果,您应该将新元素添加到数据源中,在您的函数loadSaved(numberOfPage)内{{1}} {{1}} }。

我希望这对你有所帮助。

答案 2 :(得分:2)

我修改了Victor的答案并将其用作

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正在闪烁。

答案 3 :(得分:2)

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

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

现在,我们进入拥有TableViewController的{​​{1}},并在UITableView中注册加载单元。

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

..我们返回2个部分(一个用于项,一个用于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 } } )。

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中的方法UIScrollView,来检测用户何时接近列表末尾以调用该方法…< / p>

UITableView

…loadMoreData()以下载更多数据。

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

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

enter image description here

答案 4 :(得分:1)

以上所有答案都是正确的,但对于iOS 10及更高版本,我们的回答很不错

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

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

tableView.prefetchDataSource = self

RayWeinderlich有一个很好的关于该主题的教程。由于Rays是一个可靠的网站,因此我不在此处发布代码

答案 5 :(得分:1)

拉维的答案看起来不错。但正如他最后指出的那样,如果您使用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()
        }

    }

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

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

虽然这很容易实现,但是在大型应用中,有时我们需要在很多地方实现它。为了避免这种情况,我写了一个小的framework,它是非侵入性的,可以很容易地集成。