问题
I wonder if tableview has any built-in function to add infinite scroll/pagination.
Right now my VC looks like this:
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
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
回答1:
The UITableViewDelegate has a tableView(_:willDisplay:forRowAt:) instance method which "tells the delegate the table view is about to draw a cell for a particular row."
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...
回答2:
No, the UITableView
has not any built-in function to achieve the infinite scroll or load on-demand cells like you want. What you can use is the function scrollViewDidScroll(_:) in the UIScrollViewDelegate
implemented by default in the UITableView
and in this way know when the user scroll more than the original height defined in the 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 UITableView
you should add the new elements to the data source, in your case data
inside your function loadSaved(numberOfPage)
.
I hope this help you.
回答3:
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.
回答4:
All the above answers are correct but for iOS 10 and above we have a very nice
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
This is a prefetch delegate which needs to be set
tableView.prefetchDataSource = self
RayWeinderlich has a nice tutorial on the topic. Since Rays is a dependable site i am not posting code here
回答5:
Ravi's answer looks good. But as he pointed out in the end, the tableView flickers a lot if you use scrollViewDidScroll(_ scrollView: UIScrollView)
This is because you are trying to reload tableView every time you are scrolling the 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.
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:
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
}
}
来源:https://stackoverflow.com/questions/39215081/swift-ios-add-infinite-scroll-pagination-to-uitableview