UITableView分页,将显示无限加载
Posted
技术标签:
【中文标题】UITableView分页,将显示无限加载【英文标题】:UITableView pagination, willDisplay loading infinitely 【发布时间】:2018-10-24 16:46:39 【问题描述】:我正在尝试在我的应用程序中实现聊天功能,该功能将模仿 iMessages 的拉动以加载更多消息。我的 API 在每次调用中发送 20 条消息以及 pageIndex 和其他值以跟踪页面和消息。
我正在使用 TableView willDisplay 实现分页并拉动刷新功能。
我无法添加正确的逻辑来在 willDisplay 中加载更多消息,它会进入无限循环。任何人都可以通过查看下面的代码指出我正确的方向吗?
import UIKit
class ChatViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate
@IBOutlet weak var messagesTable: UITableView!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var messages: Messages!
var messageArray = [Message]()
// Pagination
var isLoading = false
var pageSize = 10
var totalPages: Int!
var currentPage: Int!
// Pull To Refresh
let refreshControl = UIRefreshControl()
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
activityIndicator.startAnimating()
fetchMessages(page: 1, completed:
self.totalPages = self.messages.pageCount
self.currentPage = self.messages.currentPage
// Sort message by ID so that latest message appear at the bottom.
self.messageArray = self.messages.messages!.sorted(by: $0.id! < $1.id!)
self.messagesTable.reloadData()
// Scroll to the bottom of table
self.messagesTable.scrollToBottom(animated: false)
self.activityIndicator.stopAnimating()
)
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int
return 1
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return messageArray.count
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
if !self.isLoading && indexPath.row == 0
self.isLoading = true
fetchMessages(page: self.currentPage, completed:
if self.currentPage == 0
self.messageArray.removeAll()
self.messageArray.append(contentsOf: self.messages!.messages!)
self.messageArray = self.messageArray.sorted(by: $0.id! < $1.id!)
self.messagesTable.reloadData()
// Scroll to the top
self.messagesTable.scrollToRow(at: indexPath, at: UITableViewScrollPosition.top, animated: true)
self.currentPage = self.currentPage + 1
)
self.isLoading = false
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as? MessageCell else
fatalError("Can't find cell")
return cell
private func fetchMessages(page: Int, completed: @escaping () -> ())
guard let url = URL(string: "http://example.com/....") else return
URLSession.shared.dataTask(with: url) (data, response, error) in
if error != nil
print("Error in fetching data..........")
print(error!.localizedDescription)
guard let data = data else return
if let str = String(data: data, encoding: .utf8) print(str)
do
let resultData = try JSONDecoder().decode(messagesStruct.self, from: data)
DispatchQueue.main.async
print("DispatchQueue.main.async")
self.messages = resultData.data!
completed()
catch let jsonError
print(jsonError)
.resume()
//Pull to refresh
@objc func refresh(_ refreshControl: UIRefreshControl)
fetchMessages(completed:
self.messagesTable.reloadData()
)
refreshControl.endRefreshing()
【问题讨论】:
【参考方案1】:willDisplayCell
不是检查 tableView 是否真的滚动到底部的安全位置,而是使用 scrollViewDelegate
func scrollViewDidScroll(_ scrollView: UIScrollView)
if !self.isLoading && (messagesTable.contentOffset.y >= (messagesTable.contentSize.height - messagesTable.frame.size.height))
self.isLoading = true
fetchMessages(page: self.currentPage, completed: [weak self]
guard let strongSelf = self else
return
strongSelf.isLoading = false
if strongSelf.currentPage == 0
strongSelf.messageArray.removeAll()
strongSelf.messageArray.append(contentsOf: strongSelf.messages!.messages!)
strongSelf.messageArray = strongSelf.messageArray.sorted(by: $0.id! < $1.id!)
strongSelf.messagesTable.reloadData()
strongSelf.currentPage = strongSelf.currentPage + 1
)
希望对你有帮助
【讨论】:
Tx,我试过了。第一个问题是 scrollViewDidScroll 在调用任何 viewXYZAppear 方法之前就被调用了,它会进入 fetch & reload 表。这正常吗? @davems :我个人更喜欢这样,而不是在 viewWillAppear 中手动调用fetchMessages(page: 1,
,但是很难相信当 tableView 条件中没有数据时 (messagesTable.contentOffset.y >= (messagesTable.contentSize.height - messagesTable.frame.size.height)
会通过
@davems :但是如果由于任何奇怪的原因发生这种情况,它将使您免于手动调用 fetchMessages(page: 1,
这更清洁 :) 它有点创建自启动加载器机制 :) 但我几乎不怀疑 scrollViewDidScroll如果它一开始就没有内容,将永远被调用,即使它被调用也非常怀疑它是否会通过条件。请放一个断点再检查一遍
这是在调用任何 viewXXXApepar 之前的第一次打印:isLoading: false messagesTable.contentOffset.y: 0.0 messagesTable.contentSize.height: 0.0 messagesTable.frame.size.height: 590.0 条件变为是的。
@davems : 嗯,有趣,给我一秒钟 :) 但请相信我注释掉你的 viewWillAppear
s fetchMessages(page: 1,
,你会发现你有一个很好的分页系统,它可以自己启动:P 虽然启动本身不是直到那时的意图让我检查一下我是如何解决的以上是关于UITableView分页,将显示无限加载的主要内容,如果未能解决你的问题,请参考以下文章