Swift tableView分页

我有成功的工作与JSONparsing代码tableview.But可能有1000多个项目,所以需要分页滚动底部。 我不知道我怎么能这样做我的代码在下面。 对于Objective-C有很多例子,但对于迅速我没有find工作的例子。 我在等你的帮助。 我想会帮助太多的人。 谢谢 !

import UIKit class ViewController: UIViewController, UITableViewDataSource,UITableViewDelegate { let kSuccessTitle = "Congratulations" let kErrorTitle = "Connection error" let kNoticeTitle = "Notice" let kWarningTitle = "Warning" let kInfoTitle = "Info" let kSubtitle = "You've just displayed this awesome Pop Up View" @IBOutlet weak var myTableView: UITableView! @IBOutlet weak var myActivityIndicator: UIActivityIndicatorView! var privateList = [String]() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) loadItems() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } internal func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return privateList.count } internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell:myCell = tableView.dequeueReusableCellWithIdentifier("myCell") as! myCell cell.titleLabel.text = privateList[indexPath.row] return cell } func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if (editingStyle == UITableViewCellEditingStyle.Delete){ print(indexPath.row) let alert = SCLAlertView() alert.addButton("Hayır"){ } alert.addButton("Evet") { self.myTableView.beginUpdates() self.privateList.removeAtIndex(indexPath.row) tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Left) print("Silindi") self.myTableView.endUpdates() self.loadItems() } alert.showSuccess(kSuccessTitle, subTitle: kSubtitle) } } func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { // the cells you would like the actions to appear needs to be editable return true } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if(segue.identifier == "Detail") { let destinationView = segue.destinationViewController as! DetailViewController if let indexPath = myTableView.indexPathForCell(sender as! UITableViewCell) { destinationView.privateLista = privateList[indexPath.row] } } } internal func tableView(tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { return 0.0 } func loadItems() { loadItemsNow("privateList") } func loadItemsNow(listType:String){ myActivityIndicator.startAnimating() let listUrlString = "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString let myUrl = NSURL(string: listUrlString); let request = NSMutableURLRequest(URL:myUrl!); request.HTTPMethod = "GET"; let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in if error != nil { print(error!.localizedDescription) dispatch_async(dispatch_get_main_queue(),{ self.myActivityIndicator.stopAnimating() }) return } do { let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray if let parseJSON = json { self.privateList = parseJSON as! [String] } } catch { print(error) } dispatch_async(dispatch_get_main_queue(),{ self.myActivityIndicator.stopAnimating() self.myTableView.reloadData() }) } task.resume() } } 

为此,您还需要更改服务器端。

  1. 服务器将接受API url中的fromIndexbatchSize作为查询参数。

     let listUrlString = "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString + "&batchSize=" + batchSize + "&fromIndex=" + fromIndex 
  2. 在服务器响应中,将会有一个额外的关键totalItems 。 这将用于识别所有项目是否收到。 一个数组或从batchSizebatchSize的项目数。

在应用程序方面

  1. 第一个loadItem()将使用fromIndex = 0batchSize = 20 (例如在viewDidLoad()viewWillAppear )中调用。 在第一次调用loadItem()之前,从privateList数组中loadItem()

  2. 服务器返回前20个项目和totalItems服务器中项目总数的数组。

  3. privateList数组中追加20个项目并重新加载tableView

  4. tableView:cellForRowAtIndexPath方法中检查单元格是否是最后一个单元格。 并检查totalItems (表单服务器)是否大于privateList.count 。 这意味着要加载的服务器中有更多的项目

     if indexPath.row == privateList.count - 1 { // last cell if totalItems > privateList.count { // more items to fetch loadItem() // increment `fromIndex` by 20 before server call } } 

问题: where is refresh ? will be scrolling ? where is refresh ? will be scrolling ?

收到服务器响应后,在数组中追加新项后刷新。 (步骤3)

当用户滚动时,滚动将为每个单元格触发tableView:cellForRowAtIndexPath 。 代码正在检查它是否是最后一个单元格并提取剩余的项目。 (步骤4)

示例项目添加:
https://github.com/rishi420/TableViewPaging

好的和有效的方法是通过在tableview中使用scrollviewDelegate只需在scrollviewDelegate中添加UIScrollViewDelegate在视图控制器

 //For Pagination var isDataLoading:Bool=false var pageNo:Int=0 var limit:Int=20 var offset:Int=0 //pageNo*limit var didEndReached:Bool=false viewDidLoad(_){ tableview.delegate=self //To enable scrollviewdelegate } 

覆盖这个委托的两个方法

 func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { print("scrollViewWillBeginDragging") isDataLoading = false } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { print("scrollViewDidEndDecelerating") } //Pagination func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { print("scrollViewDidEndDragging") if ((tableView.contentOffset.y + tableView.frame.size.height) >= tableView.contentSize.height) { if !isDataLoading{ isDataLoading = true self.pageNo=self.pageNo+1 self.limit=self.limit+10 self.offset=self.limit * self.pageNo loadCallLogData(offset: self.offset, limit: self.limit) } } } 

添加另一个部分到你的tableview,让这个部分只有1行,这将是一个单元格包含一个活动指标,以表示加载。

 internal func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 2; } internal func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if section == 0 { return privateList.count } else if section == 1 { // this is going to be the last section with just 1 cell which will show the loading indicator return 1 } } internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { if section == 0 { let cell:myCell = tableView.dequeueReusableCellWithIdentifier("myCell") as! myCell cell.titleLabel.text = privateList[indexPath.row] return cell } else if section == 1 { //create the cell to show loading indicator ... //here we call loadItems so that there is an indication that something is loading and once loaded we relaod the tableview self.loadItems() } } 

这样做的另一种方法是:您可以设置每个发送请求时获取元素的阈值:

可以说你第一次拿20个元素。 您将保存上次获取的loggingID或编号,以获取下20个元素的列表。

 let lastFetchedIndex = 20; 

我假设你已经在myArray中添加了这些logging。 MyArray是tableView的数据源。 现在myArray包含40个对象。 现在我要创build一个需要在tableView中插入的行的indexPath列表。

 var indexPathsArray = [NSIndexPath]() for index in lastFetchedIndex..<myArray.count{ let indexPath = NSIndexPath(forRow: index, inSection: 0) indexPathsArray.append(indexPath) } 

在这里,我正在更新我的tableView。 确保你的dataSource我的意思是你的myArray已经被更新了。 以便它可以正确插入行。

 self.tableView.beginUpdates() tableView!.insertRowsAtIndexPaths(indexPathsArray, withRowAnimation: .Fade) self.tableView.endUpdates() 

我需要一个类似的项目,我的解决scheme是:

1 – 创build一个variablesnumberOfObjectsInSubArray(初始值30或任何你想要的)

2 – 创build一个子arrays,从您的privateList数组中添加一些对象,每次点击“显示更多”

  let subArray = privateList?.subarrayWithRange(NSMakeRange(0, numberOfObjectsInSubArray)) 

并使用它

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

3-无论何时您需要展示更多的物品,请执行以下操作:

 func addMoreObjectsOnTableView () { numberOfObjectsInSubArray += 30 if (numberOfObjectsInSubArray < privateList.count) { subArray = privateList?.subarrayWithRange(NSMakeRange(0, numberOfObjectsInSubArray)) } else { subArray = privateList?.subarrayWithRange(NSMakeRange(0, privateList.count)) } tableView.reloadData() } 

我希望它有帮助

这里是集合视图的示例代码:

 var page = 0 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{ print("page Num:\(page)") } func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath){ if arrImagesData.count-1 == indexPath.row && arrImagesData.count%10 == 0{ getMoreImages(page) } } func getMoreImages(page:Int){ //hit api if api_success == true { if self.page == 0 { self.arrImagesData.removeAll() } self.arrImagesData.appendContentsOf(api_data) self.collectionImages.reloadData() self.page = self.page + 1 } } 

SWIFT 3.0 – 4 …

如果您在API请求中发送页码,那么这是在您的应用中实现分页的理想方式。

1)声明variables当前页面的初始值为0和布尔值来检查是否有任何列表正在加载初始值为假

 var currentPage : Int = 0 var isLoadingList : Bool = false 

2)这是获取列表示例的函数:

  func getListFromServer(_ pageNumber: Int){ self.isloadingList = false self.table.reloadData() } 

3)这是增加页码和调用API函数的函数

  func loadMoreItemsForList(){ currentPage += 1 getListFromServer(currentPage) } 

4)这是scrollView滚动时将被调用的方法

 func scrollViewDidScroll(_ scrollView: UIScrollView) { if (((scrollView.contentOffset.y + scrollView.frame.size.height) > scrollView.contentSize.height ) && ! isLoadingList){ self. isLoadingList = true self. loadMoreItemsForList() } } 

PS的bool isLoadingList的作用是防止滚动视图从一个拖动中获取更多的列表到视图的底部。

在iOS10中添加一个新的协议现在有点简单了: UITableViewDataSourcePrefetching

https://developer.apple.com/documentation/uikit/uitableviewdatasourceprefetching