rok*_*idi 88 iphone pagination uitableview ios
我正在开发一个使用SQLite的应用程序.我想使用分页机制显示用户列表(UITableView).任何人都可以告诉我当用户滚动到列表末尾时如何在我的列表中加载更多数据(比如在Facebook应用程序的主页上)?
shi*_*yuX 102
您可以通过添加检查cellForRowAtIndexPath:方法中的位置来实现.这种方法易于理解和实现:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Classic start method
static NSString *cellIdentifier = @"MyCell";
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MainMenuCellIdentifier];
}
MyData *data = [self.dataArray objectAtIndex:indexPath.row];
// Do your cell customisation
// cell.titleLabel.text = data.title;
BOOL lastItemReached = [data isEqual:[[self.dataArray] lastObject]];
if (!lastItemReached && indexPath.row == [self.dataArray count] - 1)
{
[self launchReload];
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:添加了对最后一项的检查以防止递归调用.您必须实现定义是否已到达最后一个项目的方法.
EDIT2:解释了lastItemReached
Sur*_*gch 55
方法1:滚动到底部
这是Swro版本的PedroRomão的答案.当用户停止滚动时,它会检查它是否已到达底部.
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// UITableView only moves in one direction, y axis
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
// Change 10.0 to adjust the distance from bottom
if maximumOffset - currentOffset <= 10.0 {
self.loadMore()
}
}
Run Code Online (Sandbox Code Playgroud)
方法2:到达最后一行
这是swinguX的答案的Swift版本.它检查用户是否已到达最后一行.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// set up cell
// ...
// Check if the last row number is the same as the last current data element
if indexPath.row == self.dataArray.count - 1 {
self.loadMore()
}
}
Run Code Online (Sandbox Code Playgroud)
loadMore()方法示例我设置了这三个类变量来获取批量数据.
// number of items to be fetched each time (i.e., database LIMIT)
let itemsPerBatch = 50
// Where to start fetching items (database OFFSET)
var offset = 0
// a flag for when all database items have already been loaded
var reachedEndOfItems = false
Run Code Online (Sandbox Code Playgroud)
这是将更多项目从数据库加载到表视图中的功能.
func loadMore() {
// don't bother doing another db query if already have everything
guard !self.reachedEndOfItems else {
return
}
// query the db on a background thread
DispatchQueue.global(qos: .background).async {
// determine the range of data items to fetch
var thisBatchOfItems: [MyObjects]?
let start = self.offset
let end = self.offset + self.itemsPerBatch
// query the database
do {
// SQLite.swift wrapper
thisBatchOfItems = try MyDataHelper.findRange(start..<end)
} catch _ {
print("query failed")
}
// update UITableView with new batch of items on main thread after query finishes
DispatchQueue.main.async {
if let newItems = thisBatchOfItems {
// append the new items to the data source for the table view
self.myObjectArray.appendContentsOf(newItems)
// reload the table view
self.tableView.reloadData()
// check if this was the last of the data
if newItems.count < self.itemsPerBatch {
self.reachedEndOfItems = true
print("reached end of data. Batch count: \(newItems.count)")
}
// reset the offset for the next data query
self.offset += self.itemsPerBatch
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Sur*_*kar 36
最好使用willDisplayCell方法来检查是否将加载哪个单元格.一旦我们得到indexPath.row最后的电流,我们可以加载更多的单元格.这将在向下滚动时加载更多单元格.
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// check if indexPath.row is last row
// Perform operation to load new Cell's.
}
Run Code Online (Sandbox Code Playgroud)
Vas*_*huk 18
Xcode 10,Swift 4.2
使用UIScrollView/UICollectionView/UITableView
import UIKit
protocol LoadMoreControlDelegate: class {
func loadMoreControl(didStartAnimating loadMoreControl: LoadMoreControl)
func loadMoreControl(didStopAnimating loadMoreControl: LoadMoreControl)
}
class LoadMoreControl {
private let spacingFromLastCell: CGFloat
private let indicatorHeight: CGFloat
private weak var activityIndicatorView: UIActivityIndicatorView?
private weak var scrollView: UIScrollView?
weak var delegate: LoadMoreControlDelegate?
private var defaultY: CGFloat {
guard let height = scrollView?.contentSize.height else { return 0.0 }
return height + spacingFromLastCell
}
init (scrollView: UIScrollView, spacingFromLastCell: CGFloat, indicatorHeight: CGFloat) {
self.scrollView = scrollView
self.spacingFromLastCell = spacingFromLastCell
self.indicatorHeight = indicatorHeight
let size:CGFloat = 40
let frame = CGRect(x: (scrollView.frame.width-size)/2, y: scrollView.contentSize.height + spacingFromLastCell, width: size, height: size)
let activityIndicatorView = UIActivityIndicatorView(frame: frame)
activityIndicatorView.color = .black
activityIndicatorView.hidesWhenStopped = true
activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
scrollView.addSubview(activityIndicatorView)
activityIndicatorView.isHidden = isHidden
self.activityIndicatorView = activityIndicatorView
}
private var isHidden: Bool {
guard let scrollView = scrollView else { return true }
return scrollView.contentSize.height < scrollView.frame.size.height
}
func didScroll() {
guard let scrollView = scrollView, let activityIndicatorView = activityIndicatorView else { return }
let offsetY = scrollView.contentOffset.y
activityIndicatorView.isHidden = isHidden
if !activityIndicatorView.isHidden && offsetY >= 0 {
let contentDelta = scrollView.contentSize.height - scrollView.frame.size.height
let offsetDelta = offsetY - contentDelta
let newY = defaultY-offsetDelta
if newY < scrollView.frame.height {
activityIndicatorView.frame.origin.y = newY
} else {
if activityIndicatorView.frame.origin.y != defaultY {
activityIndicatorView.frame.origin.y = defaultY
}
}
if !activityIndicatorView.isAnimating {
if offsetY > contentDelta && offsetDelta >= indicatorHeight && !activityIndicatorView.isAnimating {
activityIndicatorView.startAnimating()
delegate?.loadMoreControl(didStartAnimating: self)
}
}
if scrollView.isDecelerating {
if activityIndicatorView.isAnimating && scrollView.contentInset.bottom == 0 {
UIView.animate(withDuration: 0.3) { [weak self, weak scrollView] in
if let bottom = self?.indicatorHeight {
scrollView?.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: bottom, right: 0)
}
}
}
}
}
}
func stop() {
guard let scrollView = scrollView else { return }
let contentDelta = scrollView.contentSize.height - scrollView.frame.size.height
let offsetDelta = scrollView.contentOffset.y - contentDelta
if offsetDelta >= 0 {
UIView.animate(withDuration: 0.3, animations: { [weak scrollView] in
scrollView?.contentInset = .zero
}) { [weak self] result in
if result { self?.endAnimating() }
}
} else {
scrollView.contentInset = .zero
endAnimating()
}
}
private func endAnimating() {
activityIndicatorView?.stopAnimating()
delegate?.loadMoreControl(didStopAnimating: self)
}
}
Run Code Online (Sandbox Code Playgroud)
loadMoreControl = LoadMoreControl(scrollView: tableView, spacingFromLastCell: 10, indicatorHeight: 60)
loadMoreControl.delegate = self
Run Code Online (Sandbox Code Playgroud)
extension ViewController: LoadMoreControlDelegate {
func loadMoreControl(didStartAnimating loadMoreControl: LoadMoreControl) {
print("didStartAnimating")
}
func loadMoreControl(didStopAnimating loadMoreControl: LoadMoreControl) {
print("didStopAnimating")
}
}
extension ViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
loadMoreControl.didScroll()
}
}
Run Code Online (Sandbox Code Playgroud)
sam*_*ize 17
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger lastSectionIndex = [tableView numberOfSections] - 1;
NSInteger lastRowIndex = [tableView numberOfRowsInSection:lastSectionIndex] - 1;
if ((indexPath.section == lastSectionIndex) && (indexPath.row == lastRowIndex)) {
// This is the last cell
[self loadMore];
}
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Core Data NSFetchedResultsController,则loadMore可能如下所示:
// Load more
- (void)loadMore {
[self.fetchedResultsController.fetchRequest setFetchLimit:newFetchLimit];
[NSFetchedResultsController deleteCacheWithName:@"cache name"];
NSError *error;
if (![self.fetchedResultsController performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
[self.tableView reloadData];
}
Run Code Online (Sandbox Code Playgroud)
Yog*_*tel 12
Loadmore 的遗传 UITableView 扩展。
在你的新文件中添加这个 UITableView + Extension
extension UITableView {
func indicatorView() -> UIActivityIndicatorView{
var activityIndicatorView = UIActivityIndicatorView()
if self.tableFooterView == nil {
let indicatorFrame = CGRect(x: 0, y: 0, width: self.bounds.width, height: 80)
activityIndicatorView = UIActivityIndicatorView(frame: indicatorFrame)
activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
if #available(iOS 13.0, *) {
activityIndicatorView.style = .large
} else {
// Fallback on earlier versions
activityIndicatorView.style = .whiteLarge
}
activityIndicatorView.color = UIColor().ThemeColor
activityIndicatorView.hidesWhenStopped = true
self.tableFooterView = activityIndicatorView
return activityIndicatorView
}
else {
return activityIndicatorView
}
}
func addLoading(_ indexPath:IndexPath, closure: @escaping (() -> Void)){
indicatorView().startAnimating()
if let lastVisibleIndexPath = self.indexPathsForVisibleRows?.last {
if indexPath == lastVisibleIndexPath && indexPath.row == self.numberOfRows(inSection: 0) - 1 {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
}
}
}
}
func stopLoading() {
if self.tableFooterView != nil {
self.indicatorView().stopAnimating()
self.tableFooterView = nil
}
else {
self.tableFooterView = nil
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,只需在 UITableViewDelegate 方法 willDisplay Cell 在您的 ViewController 中添加以下代码行并确保 tableView.delegate = self
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// need to pass your indexpath then it showing your indicator at bottom
tableView.addLoading(indexPath) {
// add your code here
// append Your array and reload your tableview
tableView.stopLoading() // stop your indicator
}
}
Run Code Online (Sandbox Code Playgroud)
就是这样..希望这有帮助。谢谢你
Ped*_*mão 11
我已经实现了一个我在stackoverflow中找到的解决方案,它工作正常,但我认为shinyuX的解决方案很容易实现,并且对我的建议工作正常.如果有人想要一个不同的解决方案可以使用下面这个.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
// UITableView only moves in one direction, y axis
CGFloat currentOffset = scrollView.contentOffset.y;
CGFloat maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
//NSInteger result = maximumOffset - currentOffset;
// Change 10.0 to adjust the distance from bottom
if (maximumOffset - currentOffset <= 10.0) {
[self loadOneMorePage];
//[self methodThatAddsDataAndReloadsTableView];
}
}
Run Code Online (Sandbox Code Playgroud)
在查询中使用限制和偏移量,并使用该内容填充tableview.当用户向下滚动时,加载下一个偏移量.
tableView:willDisplayCell:forRowAtIndexPath:在你的实现方法,UITableViewDelegate并检查它是否是最后一行
小智 5
下面的链接将提供示例代码.#Swift3
用户需要拉出最后一个表格视图单元格,至少需要2个单元格才能从服务器获取更多数据.
您还会发现Process cell也显示加载过程,如同最后一个单元格一样.
它在Swift3中
https://github.com/yogendrabagoriya/YBTableViewPullData
另一种可供使用的选项(Swift 3和 iOS 10+):
class DocumentEventsTableViewController: UITableViewController, UITableViewDataSourcePrefetching {
var currentPage: Int = 1
let pageSize: Int = 10 // num of items in one page
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.prefetchDataSource = self
}
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
let upcomingRows = indexPaths.map { $0.row }
if let maxIndex = upcomingRows.max() {
let nextPage: Int = Int(ceil(Double(maxIndex) / Double(pageSize))) + 1
if nextPage > currentPage {
// Your function, which attempts to load respective page from the local database
loadLocalData(page: nextPage)
// Your function, which makes a network request to fetch the respective page of data from the network
startLoadingDataFromNetwork(page: nextPage)
currentPage = nextPage
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于相当小的页面(~ 10 个项目),您可能需要手动添加第 1 和第 2 页的数据,因为 nextPage 可能位于大约 1-2 的某个位置,直到表格有几个项目可以很好地滚动。但它对于接下来的所有页面都非常有用。
| 归档时间: |
|
| 查看次数: |
121073 次 |
| 最近记录: |