/TableviewPaginator

UITableview Pagination, Made easy !!!

Primary LanguageSwiftMIT LicenseMIT

CI Status codebeat badge Version Carthage compatible License Platform Xcode Swift

Example

To run the example project

pod try TableviewPaginator

Installation

CocoaPods

TableviewPaginator is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'TableviewPaginator' 
Carthage

TableviewPaginator is available throguh Carthage, specify it in your Cartfile:

github "ratulSharker/TableviewPaginator" ~> 0.3.3
Manually

Add the TableviewPaginator.swift file to your Xcode project and you are good to go.

Usage

Step 1: Import the TableviewPaginator module in swift.

import TableviewPaginator

Step 2: Take a reference to TableviewPaginator (say tableviewPaginator) into your controller. This example assumes that you use UIViewController as your controller.

private var tableviewPaginator: TableviewPaginator?

Step 3: Initialize the tableviewPaginator in your viewDidLoad callback. Note that, before doing initialSetup method call, initialize your viewModel classes (from where you supply the data to view controller).

override func viewDidLoad() {
  // do all you model setup before initializing the tableviewPaginator
  tableviewPaginator = TableviewPaginator.init(paginatorUI: self, delegate: self)
  tableviewPaginator?.initialSetup()
}

Step 4: Now we have to implement two protocol TableviewPaginatorUIProtocol & TableviewPaginatorProtocol. TableviewPaginatorUIProtocol is responsible for specifying the tableview to working on and some other UI stuffs. TableviewPaginatorProtocol is responsible for let you know when to load and which data segment to load. The reason behind putting them inside of two different protocol is that, you may introduce a new class which is responsible for implementing TableviewPaginatorUIProtocol and keep the TableviewPaginatorProtocol implementation in your controller.

Implementing TableviewPaginatorUIProtocol

extension YourViewController: TableviewPaginatorUIProtocol {
    func getTableview(paginator: TableviewPaginator) -> UITableView {
        return yourTableview
    }

    func shouldAddRefreshControl(paginator: TableviewPaginator) -> Bool {
        return true
    }

    func getPaginatedLoadMoreCellHeight(paginator: TableviewPaginator) -> CGFloat {
        return 44
    }

    func getPaginatedLoadMoreCell(paginator: TableviewPaginator) -> UITableViewCell {
        if let cell = yourTableview.dequeueReusableCell(withIdentifier: "YOUR_LOAD_MORE_CELL_IDENTIFIER") as? YourLoadMoreCell {
            // customize your load more cell
            // i.e start animating the UIActivityIndicator inside of the cell
            return cell
        } else {
            return UITableViewCell.init()
        }
    }

    func getRefreshControlTintColor(paginator: TableviewPaginator) -> UIColor {
        return yourColorOfChoice
    }
}

Implementing TableviewPaginatorProtocol

extension YourViewController: TableviewPaginatorProtocol {
    func loadPaginatedData(offset: Int, shouldAppend: Bool, paginator: TableviewPaginator) {
        // call your data populating method here
        // i.e given below
        yourViewModel?.fetchData(offset: offset, limit: yourDataFetchLimit, shouldAppend: shouldAppend)
    }
}

Step 5: Now you have to call some methods from UITableViewDelegate, UITableViewDataSource & your data fetched callbacks.

inside of heightForRowAt call heightForLoadMore as following.

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // if the current indexPath should show the Load more cell
    // then heightForLoadMore will return a valid height
    // height provided in the TableviewPaginatorUIProtocol
    if let height = tableviewPaginator?.heightForLoadMore(cell: indexPath) {
        return height
    }

    return yourCellHeight
}

inside of scrollViewDidScroll will look like follwoing. scrollViewDidScroll is inherited from UIScrollViewDelegate.

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
      tableviewPaginator?.scrollViewDidScroll(scrollView)
  }

inside of numberOfRowsInSection, call rowsIn as following

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let yourCurrentNumberOfRows
    let tableviewPagiantorLoadeMoreCells = (tableviewPaginator?.rowsIn(section: section) ?? 0)
    return yourCurrentNumberOfRows + tableviewPagiantorLoadeMoreCells
}

inside of cellForRowAt, call cellForLoadMore as following

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if let cell = tableviewPaginator?.cellForLoadMore(at: indexPath) {
        return cell
    }

    // write your own cell returning logic
}

All of this implementation was very straight forward. The last task is to, let tableviewPaginator know that you have successfully completed the data fetching. This requires a function call from your data fetch completion delegate / code block. Here i assume that, you provide a delegate by the viewModel & implement that delegate in your viewController. There must be a method saying that dataFetched. Implemetation will look like following

extension YourViewController: YourViewModelProtocol {
    func dataFetched(success: Bool, dataCount: Int) {
        if success {
            tableviewPaginator?.incrementOffsetBy(delta: userCount)
        }

        tableviewPaginator?.partialDataFetchingDone()

        yourTableView.reloadData()
    }
}

Here the dataCount parameter denoting the newly added number of data, more precisely newly added number of rows.

Tips

  1. TableviewPaginator is a pure swift class. If you intend to use multiple paginator in the single view controller (use case like, showing two different tableview in a single view controller, switching between them using the Segmented control) you may want to check against the passed paginator object for identifying which paginator is calling this delegate method. In that case user === Identity Operators to check for reference equality.
  2. Whenever you want to know that any data fetching is running or not use YOUR_PAGINATOR.state.dataFetchingRunning. This Bool will let you know that status. To check that all the data (all the pages) use YOUT_PAGINATOR.state.allDataFetchingCompleted this Bool. To know about the current offset use state.offset.

Author

sharker.ratul.08@gmail.com

License

TableviewPaginator is available under the MIT license. See the LICENSE file for more info.