swift ios 向 uitableview 添加无限滚动分页
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39215081/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
swift ios add infinite scroll pagination to uitableview
提问by user2636197
I wonder if tableview has any built-in function to add infinite scroll/pagination.
我想知道 tableview 是否有任何内置函数来添加无限滚动/分页。
Right now my VC looks like this:
现在我的 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)
}
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
我使用loadSaved(1)通过为函数提供我想要加载的当前页面来获取我的数据。该函数使用 alomofire 发出 API 请求,然后填充var 数据:JSON!= []带有应显示的数据
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
所以我想要做的是当我滚动到 tableview 的底部时loadSaved(2)应该被称为将更多数据加载到 tableview
回答by lukkea
The UITableViewDelegate has a table?View(_:?will?Display:?for?Row?At:?) instance methodwhich "tells the delegate the table view is about to draw a cell for a particular row."
UITableViewDelegate 有一个table?View(_:?will?Display:?for?Row?At:?) 实例方法,它“告诉委托表视图即将为特定行绘制一个单元格。”
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...
根据您的代码,您可能需要对此进行一些检查,以确保在您加载了所有数据后不会陷入无限循环......
回答by Victor Sigler
No, the UITableView
has not any built-in function to achieve the infinite scroll or load on-demandcells 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
.
不,UITableView
它没有任何内置功能来实现您想要的无限滚动或按需加载单元格。您可以使用的是默认实现的功能scrollViewDidScroll(_:)
,并UIScrollViewDelegate
通过UITableView
这种方式知道用户何时滚动超过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)
.
要实现在末尾添加其余元素的结果,UITableView
您应该将新元素添加到数据源中,在您的情况下是data
在您的函数中loadSaved(numberOfPage)
。
I hope this help you.
我希望这对你有帮助。
回答by Ravi_sankar
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.
接收数据时将 loadingStatus 重置为 true。没有检查视图是否已经加载了更多数据,tableview 正在闪烁。
回答by amar
All the above answers are correct but for iOS 10 and above we have a very nice
以上所有答案都是正确的,但对于 iOS 10 及更高版本,我们有一个非常好的
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
This is a prefetch delegate which needs to be set
这是一个需要设置的预取委托
tableView.prefetchDataSource = self
RayWeinderlichhas a nice tutorial on the topic. Since Rays is a dependable site i am not posting code here
RayWeinderlich有一个关于这个主题的不错的教程。由于 Rays 是一个可靠的网站,我不会在这里发布代码
回答by iPhoneDeveloper
Ravi's answer looks good. But as he pointed out in the end, the tableView flickersa lot if you use scrollViewDidScroll(_ scrollView: UIScrollView)
拉维的回答看起来不错。但正如他最后指出的那样,如果您使用,tableView 会闪烁很多scrollViewDidScroll(_ scrollView: UIScrollView)
This is because you are trying to reload tableView every time you are scrolling the tableView.
这是因为您每次滚动 tableView 时都试图重新加载 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.
相反,您可以使用 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()
}
}
回答by Kraming
There are number of ways we can do this. The essense of all different ways, is to load next set of data when user scroll to last. I have implemented it via adding an extra special cell at the end of tableView and when that cell gets loaded in willDisplay cell: forRowAtIndexPath:
which triggers next set of fetching of data.
我们有很多方法可以做到这一点。所有不同方式的本质是当用户滚动到最后一组时加载下一组数据。我已经通过在 tableView 的末尾添加一个额外的特殊单元格来实现它,并且当该单元格被加载时willDisplay cell: forRowAtIndexPath:
会触发下一组数据获取。
Athough this is simple to implement but in larger apps at times we need to implement it many places. To avoid this, I wrote a small frameworkwhich is non-intrusive and can be easyly integrated.
虽然这很容易实现,但在较大的应用程序中,有时我们需要在很多地方实现它。为了避免这种情况,我编写了一个非侵入性且易于集成的小框架。
回答by Vishal Wagh
Above Ans are also right, but may be some one help out this code also.
上面的 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
}
}