当Facebook应用程序滚动到底部时,UITableView加载更多

 J品1北京天7W乐 发布于 2023-02-14 05:09

我正在开发一个使用SQLite的应用程序.我想使用分页机制显示用户列表(UITableView).任何人都可以告诉我当用户滚动到列表末尾时如何在我的列表中加载更多数据(比如在Facebook应用程序的主页上)?

6 个回答
  • 您可以通过添加检查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];
        }
    }
    

    编辑:添加了对最后一项的检查以防止递归调用.您必须实现定义是否已到达最后一个项目的方法.

    EDIT2:解释了lastItemReached

    2023-02-14 05:14 回答
  • 迅速

    方法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()
        }
    }
    

    方法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()
        }
    
    }
    

    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
    

    这是将更多项目从数据库加载到表视图中的功能.

    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
                }
    
            }
        }
    }
    

    2023-02-14 05:14 回答
  • 最好使用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.
    }
    

    2023-02-14 05:19 回答
  • - (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];
        }
    }
    

    如果您使用的是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];
    }
    

    2023-02-14 05:21 回答
  • 细节

    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)
        }
    }
    

    用法

    loadMoreControl = LoadMoreControl(scrollView: tableView, spacingFromLastCell: 10, indicatorHeight: 60)
    loadMoreControl.delegate = self
    

    完整样本

    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()
        }
    }
    

    结果

    在此输入图像描述

    2023-02-14 05:23 回答
  • 下面的链接将提供示例代码.#Swift3

    用户需要拉出最后一个表格视图单元格,至少需要2个单元格才能从服务器获取更多数据.

    您还会发现Process cell也显示加载过程,如同最后一个单元格一样.

    它在Swift3中

    https://github.com/yogendrabagoriya/YBTableViewPullData

    2023-02-14 05:24 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有