Swift tableView分页
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift tableView分页相关的知识,希望对你有一定的参考价值。
我用json解析代码成功地工作tableview。但是可能还有1000个项目,因此在滚动底部时需要分页。我不知道我怎么能在下面做我的代码。对于objective-c有很多例子但是对于swift我没有找到工作的例子。我在等你的帮助。我想会帮助太多人。谢谢 !
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()
}
}
为此,您还需要进行服务器端更改。
- 服务器将接受
fromIndex
url中的batchSize
和API
作为查询参数。let listUrlString = "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString + "&batchSize=" + batchSize + "&fromIndex=" + fromIndex
- 在服务器响应中,将有一个额外的密钥
totalItems
。这将用于识别是否收到所有项目。一个或多个项目fromIndex
到batchSize
的项目数量。
在应用程序方面
- 首先使用
loadItem()
和fromIndex = 0
调用batchSize = 20
(例如在viewDidLoad()
或viewWillAppear
中)。在第一次调用privateList
之前,从loadItem()
数组中删除所有项目 - 服务器返回前20个项目的数组和
totalItems
服务器中的项目总数。 - 在
privateList
数组中附加20个项目并重新加载tableView
- 在
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 ?
收到服务器响应后,在数组中追加新项目后刷新。 (第3步)
当用户滚动时,滚动将为每个单元格触发tableView:cellForRowAtIndexPath
。代码正在检查它是否是最后一个单元格并获取剩余项目。 (第4步)
示例项目添加: https://github.com/rishi420/TableViewPaging
这样做的好方法是通过在tableview中使用scrollviewDelegate
只需在UIScrollViewDelegate
中添加viewController
在视图控制器中
//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)
}
}
}
SWIFT 3.0 - 4 ......
如果您要在API请求中发送页码,那么这是在您的应用中实施分页的理想方式。
1)声明具有初始值0的变量current Page和bool,以检查是否正在加载任何列表,初始值为false
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()
}
}
附: bool isLoadingList角色是为了防止滚动视图在一次拖动中获取更多列表到表视图的底部。
现在,通过在ios10中添加新协议,这会更容易一些:UITableViewDataSourcePrefetching
https://developer.apple.com/documentation/uikit/uitableviewdatasourceprefetching
在tableview中添加另一个部分,让此部分只有一行,它将是一个包含活动指示符的单元格,以表示加载。
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个元素。您将保存上次获取的记录ID或数字,以获取下20个元素的列表。
let lastFetchedIndex = 20;
我假设您已经在myArray中添加了这些记录。 MyArray是tableView的dataSource。现在myArray包含40个对象。我将创建一个需要在tableView中插入的行的indexPaths列表。
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()
我在项目上需要类似的东西,我的解决方案是:
1 - 创建一个变量numberOfObjectsInSubArray(初始值30或任何你想要的)
2 - 每次点击“显示更多”时,创建一个子阵列以从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 tableView分页的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 MovieDB API Swift 为 TableView 进行分页?
Swift中带有标题的TableView的自定义分页大小(一次滚动一个单元格)