[英]swift ios add infinite scroll pagination to uitableview
我想知道 tableview 是否有任何内置的 function 来添加无限滚动/分页。
现在我的 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)
}
我通过为 function 提供我要加载的当前页面来使用loadSaved(1)获取我的数据。 function 使用 alomofire 发出 API 请求,然后填充var 数据:JSON! = []包含应显示的数据
所以我想做的是当我滚动到 tableview 的底部时应该调用loadSaved(2)将更多数据加载到 tableview
UITableViewDelegate 有一个 tableView (_: will Display: for Row At: ) 实例方法,它“告诉委托 table view 即将为特定行绘制一个单元格。”
在你的情况下,我会像这样使用它:
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
}
}
根据您的代码,您可能需要对此进行一些检查,以确保在您加载了所有数据后不会陷入无限循环......
不, UITableView
没有任何内置函数来实现无限滚动或按需加载单元格。 您可以使用的是UIScrollViewDelegate
的函数scrollViewDidScroll(_:)
在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()
}
}
为了实现在结尾处添加元素的其余部分的结果UITableView
你应该添加新的元素到数据源,在你的情况下data
的函数中loadSaved(numberOfPage)
我希望这对你有帮助。
以上所有答案都是正确的,但对于 iOS 10 及更高版本,我们有一个非常好的
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
这是一个需要设置的预取委托
tableView.prefetchDataSource = self
RayWeinderlich有一个关于这个主题的不错的教程。 由于 Rays 是一个可靠的网站,我不会在这里发布代码
我修改了维克多的答案并将其用作,
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 正在闪烁。
首先,创建一个带有Xib
文件的UITableViewCell
并在单元格的中心添加一个UIActivityIndicatorView
。
然后, Control+left click
并将UIActivityIndicatorView
拖到您的 .swift 文件中,并命名为activityIndicator
……并添加“ loadingcellid
”作为Identifier
。
现在,让我们进入我们有UITableView
TableViewController
,并在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
方法中添加以下代码。
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
}
}
..我们返回 2 个部分(一个用于项目,一个用于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
,来自UITableView
嵌入的UIScrollView
,来检测用户何时接近列表末尾以调用该方法......
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()
}
}
... loadMoreData() 下载更多数据。
func loadMoreData() {
if !self.isLoading {
self.isLoading = true
DispatchQueue.global().async {
// Fake background loading task for 2 seconds
sleep(2)
// Download more data here
DispatchQueue.main.async {
self.tableView.reloadData()
self.isLoading = false
}
}
}
}
它运行良好,形成更多:- https://johncodeos.com/how-to-add-load-more-infinite-scrolling-in-ios-using-swift/
拉维的回答看起来不错。 但正如他最后指出的那样,如果您使用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()
}
}
上面的 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
}
}
我们有很多方法可以做到这一点。 所有不同方式的本质是当用户滚动到最后一组时加载下一组数据。 我通过在 tableView 的末尾添加一个额外的特殊单元格来实现它,当该单元willDisplay cell: forRowAtIndexPath:
载到willDisplay cell: forRowAtIndexPath:
触发下一组数据获取。
虽然这很容易实现,但在较大的应用程序中,有时我们需要在很多地方实现它。 为了避免这种情况,我编写了一个非侵入性且易于集成的小框架。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.