Skip to content

Instantly share code, notes, and snippets.

@shishirthedev
Last active May 15, 2019 05:42
Show Gist options
  • Save shishirthedev/6720e1d1e4f0b5af735182111643ebb5 to your computer and use it in GitHub Desktop.
Save shishirthedev/6720e1d1e4f0b5af735182111643ebb5 to your computer and use it in GitHub Desktop.
iOS tableview adapter custom code with pagination and refresh Control....
import UIKit
protocol SSAdapterDelegate {
func willDisplay(cell: UITableViewCell, indexPath: IndexPath)
func didSelected(indexPath: IndexPath)
func hasNextPage()->Bool
func isLoadingFooterAdded()->Bool
func loadMoreData()
func refreshTableData()
}
extension SSAdapterDelegate{
func loadMoreData(){}
func didSelected(indexPath: IndexPath){}
func hasNextPage()->Bool { return false }
func refreshTableData(){}
}
class SSAdapter<T>: NSObject, UITableViewDelegate, UITableViewDataSource{
var tv: UITableView
var cellIdentifier: String
var sDelegate: SSAdapterDelegate?
var tableData:[T] = [T]()
/* Refresh Control doesn't work properly on large title. To solve the issue set top constraint
of tableView to the super view */
lazy var refresher: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.tintColor = UIColor(hexString: colorPrimary)
refreshControl.addTarget(self, action: #selector(refreshContents), for: .valueChanged)
return refreshControl
}()
init(tableView: UITableView,
cellIdentifer: String,
sDelegate: SSAdapterDelegate) {
self.tv = tableView
self.cellIdentifier = cellIdentifer
self.sDelegate = sDelegate
super.init()
self.addRefreshControl()
}
func addRefreshControl(){
if #available(iOS 10.0, *){
self.tv.refreshControl = refresher
}else{
self.tv.addSubview(refresher)
}
}
@objc func refreshContents(){
sDelegate?.refreshTableData()
}
func isRefreshing()-> (Bool){
return refresher.isRefreshing
}
func addLoadingFooter(){
let spinner = UIActivityIndicatorView(style: .gray)
spinner.startAnimating()
spinner.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tv.bounds.width, height: CGFloat(44))
tv.tableFooterView = spinner
tv.tableFooterView?.isHidden = false
}
func removeLoadingFooter(){
tv.tableFooterView = nil
}
func addAll(itemList:[T]){
tableData += itemList
notifyDataSetChanged()
}
func addItem(item: T){
tableData.append(item)
let lastRow: Int = tv.numberOfRows(inSection: 0)
let indexPath = IndexPath(row: lastRow, section: 0);
tv.insertRows(at: [indexPath], with: .automatic)
}
func removeItem(position: Int){
tableData.remove(at: position)
let indexPath = IndexPath(row: position, section: 0);
tv.deleteRows(at: [indexPath], with: .automatic)
}
func notifyDataSetChanged(){
if refresher.isRefreshing{
refresher.endRefreshing()
}
tv.reloadData()
}
////////////////////////////////////////////////////////////////////////////
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) else { return UITableViewCell() }
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
sDelegate?.willDisplay(cell: cell, indexPath: indexPath)
if (indexPath.row == tableData.count - 1 ){
if (sDelegate?.hasNextPage() ?? false) && !(sDelegate?.isLoadingFooterAdded() ?? false) {
addLoadingFooter()
sDelegate?.loadMoreData()
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
sDelegate?.didSelected(indexPath: indexPath)
}
}
extension UITableView {
func setAdapter<T>(_ adapter: SSAdapter<T>) {
dataSource = adapter
delegate = adapter
tableFooterView = UIView(frame: CGRect.zero)
reloadData()
}
}
/////////////////////////////////////////// HOW TO USE////////////////////////////////////////////////
class LockRequestViewController: BaseViewController {
var presenter: LockRequestPresenterProtocol?
@IBOutlet weak var tableView: UITableView!
var lockRequests:[SingleLockRequest] = [SingleLockRequest]()
var nextPageUrl: String?
var isLoadingAdded: Bool = false
var adapter: SSAdapter<SingleLockRequest>!
override func viewDidLoad() {
super.viewDidLoad()
setupAddBarBtn() // Add a addLockRequest Bar button to the navigation Bar.........
adapter = SSAdapter(tableView: tableView, cellIdentifer: LockRequestTableViewCell.className, sDelegate: self)
tableView.rowHeight = 70
tableView.setAdapter(adapter)
LockRequestAllWireFrame.createLockRequestsModule(view: self)
presenter?.getLockRequestAll(url: APIs.GET_LOCK_REQUEST_ALL)
}
func setupAddBarBtn(){
let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addBtnDidTapped))
self.navigationItem.rightBarButtonItem = addBtn
}
@objc func addBtnDidTapped(){
performSegue(withIdentifier: "add_lock_request", sender: nil)
}
override func networkCallDidStarted(_ loadingMsg: String) {
if !(isLoadingAdded || adapter.isRefreshing()){
SVProgressHUD.show(withStatus: loadingMsg)
}
}
}
extension LockRequestViewController: LockRequestViewProtocol{
func lockRequestDidReceived(lock: Locks) {
if(adapter.isRefreshing()){
self.lockRequests.removeAll()
adapter.tableData.removeAll()
}
nextPageUrl = lock.nextPageURL
lockRequests += lock.data
adapter.addAll(itemList: lock.data)
if(isLoadingAdded){
isLoadingAdded = false
adapter.removeLoadingFooter()
}
}
}
extension LockRequestViewController: SSAdapterDelegate {
func isLoadingFooterAdded() -> Bool {
return isLoadingAdded
}
func loadMoreData() {
isLoadingAdded = true
presenter?.getLockRequestAll(url: nextPageUrl!)
}
func refreshTableData() {
presenter?.getLockRequestAll(url: APIs.GET_LOCK_REQUEST_ALL)
}
func hasNextPage() -> Bool {
return nextPageUrl != nil
}
func willDisplay(cell: UITableViewCell, indexPath: IndexPath) {
if (cell is LockRequestTableViewCell){
let lockCell: LockRequestTableViewCell = cell as! LockRequestTableViewCell
lockCell.configData(singleLockData: lockRequests[indexPath.row])
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment