UITableView load more when scrolling to bottom like Facebook application

后端 未结 18 2051

I am developing an application that uses SQLite. I want to show a list of users (UITableView) using a paginating mechanism. Could any one please tell me how to load more dat

相关标签:
18条回答
  • 2020-11-27 09:44

    you should check ios UITableViewDataSourcePrefetching.

    class ViewController: UIViewController {
        @IBOutlet weak var mytableview: UITableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            mytableview.prefetchDataSource = self
        }
    
     func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
            print("prefetchdRowsAtIndexpath \(indexPaths)")
        }
    
        func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
            print("cancelPrefetchingForRowsAtIndexpath \(indexPaths)")
        }
    
    
    }
    
    • https://developer.apple.com/documentation/uikit/uitableviewdatasourceprefetching https://andreygordeev.com/2017/02/20/uitableview-prefetching/
    0 讨论(0)
  • 2020-11-27 09:48

    The best way to solve this problem is to add cell at the bottom of your table, and this cell will hold indicator.

    In swift you need to add this:

    1. Create new cell of type cellLoading this will hold the indicator. Look at the code below
    2. Look at the num of rows and add 1 to it (This is for loading cell).
    3. you need to check in the rawAtIndex if idexPath.row == yourArray.count then return Loading cell.

    look at code below:

    import UIKit
    
    class LoadingCell: UITableViewCell {
    
    @IBOutlet weak var indicator: UIActivityIndicatorView!
    
    
    }
    

    For table view : numOfRows:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return  yourArray.count + 1
    }
    

    cellForRawAt indexPath:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        if indexPath.row == users.count  {
            // need to change
            let loading = Bundle.main.loadNibNamed("LoadingCell", owner: LoadingCell.self , options: nil)?.first as! LoadingCell
            return loading
    
        }
    
        let yourCell = tableView.dequeueReusableCell(withIdentifier: "cellCustomizing", for: indexPath) as! UITableViewCell
    
        return yourCell
    
    }
    

    If you notice that my loading cell is created from a nib file. This videos will explain what I did.

    0 讨论(0)
  • 2020-11-27 09:49

    Below link will provide sample code. #Swift3

    User need to pull up last table view cell, at least hight of 2 cell to fetch more data from server.

    You will found Process cell also to show loading process as in last cell.

    Its in Swift3

    https://github.com/yogendrabagoriya/YBTableViewPullData

    0 讨论(0)
  • 2020-11-27 09:49

    For Xcode 10.1, Swift 4.2

    This video seems like a great tutorial!

    Starter/Complete project: https://github.com/RobCanton/Swift-Infinite-Scrolling-Example

    import UIKit
    
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
        var tableView:UITableView!
    
        var fetchingMore = false
        var items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
            initTableView()
        }
    
        func initTableView() {
            tableView = UITableView(frame: view.bounds, style: .plain)
            tableView.register(UITableViewCell.self, forCellReuseIdentifier: "tableCell")
            tableView.delegate = self
            tableView.dataSource = self
    
            view.addSubview(tableView)
            tableView.translatesAutoresizingMaskIntoConstraints = false
    
            let layoutGuide = view.safeAreaLayoutGuide
            tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
            tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
            tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
            tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
    
            tableView.reloadData()
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return items.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
                cell.textLabel?.text = "Item \(items[indexPath.row])"
                return cell
        }
    
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let offsetY = scrollView.contentOffset.y
            let contentHeight = scrollView.contentSize.height
    
            if offsetY > contentHeight - scrollView.frame.height * 4 {
                if !fetchingMore {
                    beginBatchFetch()
                }
            }
        }
    
        func beginBatchFetch() {
            fetchingMore = true
            print("Call API here..")
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.50, execute: {
                print("Consider this as API response.")
                let newItems = (self.items.count...self.items.count + 12).map { index in index }
                self.items.append(contentsOf: newItems)
                self.fetchingMore = false
                self.tableView.reloadData()
            })
        }
    }
    
    0 讨论(0)
  • 2020-11-27 09:51

    One more option to use (Swift 3 and 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
                 }
             }
         }
     }
    

    For rather small pages (~ 10 items) you might want to manually add data for pages 1 and 2 because nextPage might be somewhere about 1-2 until the table has a few items to be scrolled well. But it will work great for all next pages.

    0 讨论(0)
  • 2020-11-27 09:52
    - (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];
        }
    }
    

    If you are using Core Data and NSFetchedResultsController, then loadMore could look like the following:

    // 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];
    }
    
    0 讨论(0)
提交回复
热议问题