我想知道tableview是否有任何内置函数来添加无限滚动/分页。
现在我的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)
}
我使用 loadSaved(1)获取数据,方法是为我要加载的当前页面提供功能。该函数使用alomofire发出API请求,然后填充 var data:JSON! = [] 包含应显示的数据
所以我想要做的是当我滚动到tableview的底部时,应该调用 loadSaved(2)将更多数据加载到tableview中
答案 0 :(得分:22)
UITableViewDelegate有一个tableView(_:willDisplay:forRowAt:) instance method,它“告诉委托表视图即将绘制特定行的单元格。”
在你的情况下,我会用这样的东西:
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
}
}
根据您的代码,您可能需要对此进行一些检查,以确保在加载所有数据后不会无限循环...
答案 1 :(得分:4)
不,UITableView
没有任何内置函数来实现无限滚动或按需添加按需单元格。您可以使用UIScrollViewDelegate
中的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()
}
}
中实现,并以这种方式知道用户何时滚动超过{{1}中定义的原始高度}。
例如,在此代码中:
UITableView
要实现在data
末尾添加其余元素的结果,您应该将新元素添加到数据源中,在您的函数loadSaved(numberOfPage)
内{{1}} {{1}} }。
我希望这对你有所帮助。
答案 2 :(得分:2)
我修改了Victor的答案并将其用作
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正在闪烁。
答案 3 :(得分:2)
首先,使用UITableViewCell
文件创建一个Xib
,并在单元格的中心添加一个UIActivityIndicatorView
。
然后,Control+left click
并将UIActivityIndicatorView
拖到您的.swift文件中,并命名为activityIndicator
……并添加'loadingcellid
'作为Identifier
。
现在,我们进入拥有TableViewController
的{{1}},并在UITableView
中注册加载单元。
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
..我们返回2个部分(一个用于项,一个用于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
}
}
)。
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
中的方法UIScrollView
,来检测用户何时接近列表末尾以调用该方法…< / p>
UITableView
…loadMoreData()以下载更多数据。
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()
}
}
它运行良好,形式更多:-https://johncodeos.com/how-to-add-load-more-infinite-scrolling-in-ios-using-swift/
答案 4 :(得分:1)
以上所有答案都是正确的,但对于iOS 10及更高版本,我们的回答很不错
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
这是一个需要设置的预取委托
tableView.prefetchDataSource = self
RayWeinderlich有一个很好的关于该主题的教程。由于Rays是一个可靠的网站,因此我不在此处发布代码
答案 5 :(得分:1)
拉维的答案看起来不错。但正如他最后指出的那样,如果您使用scrollViewDidScroll(_ scrollView: UIScrollView)
这是因为每次滚动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()
}
}
答案 6 :(得分:0)
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
}
}
答案 7 :(得分:0)
有很多方法可以做到这一点。所有不同方式的本质是在用户滚动到最后一个时加载下一组数据。我通过在tableView的末尾添加一个特殊的单元格来实现它,并且当该单元格加载到 willDisplay cell: forRowAtIndexPath:
中时,该单元格会触发下一组数据提取。
虽然这很容易实现,但是在大型应用中,有时我们需要在很多地方实现它。为了避免这种情况,我写了一个小的framework,它是非侵入性的,可以很容易地集成。