How to add pagination in UICollectionView in swift

2020-06-04 09:26发布

问题:

I have a UICollection view which shows items. Now I want to add pagination on UICollectionView. I do not want to use any third party for this functionality. Please let me know how I can achieve this!

I have four one example http://slicode.com/bottom-refresh-control-uicollectionview/

But in this I have to drag scrollview upwards for few second to make it work.

回答1:

If you want to add bottom refresh control you have to use below helper class.

https://github.com/vlasov/CCBottomRefreshControl/tree/master/Classes

Download this 2 files which is in Objective-C. You have to import this file in Bridging header

#import "UIScrollView+BottomRefreshControl.h"

Add refresh control like this.

let refreshControl = UIRefreshControl.init(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
refreshControl.triggerVerticalOffset = 50.0 
refreshControl.addTarget(self, action: #selector(paginateMore), for: .valueChanged) 
collectionView.bottomRefreshControl = refreshControl

This helper class provide you new bottomRefreshControl property, which helps you to add refresh control in bottom.



回答2:

CollectionView Delegate method: Load More data on Scroll Demand on CollectionView.

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        if indexPath.row == numberofitem.count - 1 {  //numberofitem count
            updateNextSet()  
        }
}

func updateNextSet(){
       print("On Completetion")
       //requests another set of data (20 more items) from the server.
}


回答3:

I have added the functionality of load more in one of my application so let me give you the code

    func collectionView(_ collectionView: UICollectionView, layout
        collectionViewLayout: UICollectionViewLayout,
                        referenceSizeForFooterInSection section: Int) -> CGSize {

        if arrData.count > 0 && isLastPageReached == false
        {
            return CGSize(width:(collectionView.frame.size.width), height: 100.0)
        }
        return CGSize.zero

    }
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

        if kind == UICollectionElementKindSectionFooter {

            let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "footer", for: indexPath)


            let loading = UIActivityIndicatorView()
            loading.activityIndicatorViewStyle = .gray
            loading.translatesAutoresizingMaskIntoConstraints = false
            loading.tintColor = UIColor.gray
            loading.tag = -123456
            view.addSubview(loading)
            view.addConstraint(NSLayoutConstraint(item: loading, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0))
            vew.addConstraint(NSLayoutConstraint(item: loading, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0))


            return view
        }
        return UICollectionReusableView()
    }

    func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) {
        if elementKind == UICollectionElementKindSectionFooter {

            if let loadingView = view.viewWithTag(-123456) as? UIActivityIndicatorView{
                if arrData.count > 0 && isLastPageReached == false 
                {
                    loadingView.startAnimating()
                    self.loadMore()
                }
                else
                {
                    self.isLoadMore = false
                }
            }
        }
    }
    func collectionView(_ collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, at indexPath: IndexPath) {
        if elementKind == UICollectionElementKindSectionFooter{

            if let loadingView = view.viewWithTag(-123456) as? UIActivityIndicatorView{
                loadingView.stopAnimating()
                loadingView.removeFromSuperview()

                self.isLoadMore = false
            }

        }
    }


回答4:

Please try this it works for me.

Step 1:

Declare a global variable :

var totalCount : NSInteger?
var isGetResponse : Bool = true
var activityIndiator : UIActivityIndicatorView?

Set the viewDidLoad:

activityIndiator = UIActivityIndicatorView(frame: CGRect(x: self.view.frame.midX - 15, y: self.view.frame.height - 140, width: 30, height: 30))
    activityIndiator?.activityIndicatorViewStyle = .white
    activityIndiator?.color = UIColor.black
    activityIndiator?.hidesWhenStopped = true
    activityIndiator?.backgroundColor = COLOR.COLOR_TABLEVIEW_BACKGROUND
    activityIndiator?.layer.cornerRadius = 15
    self.view.addSubview(activityIndiator!)
    self.view.bringSubview(toFront: activityIndiator!)

Step 2: Set the value in the api call method:

self.totalCount = array.count
self.isGetResponse = true

Step 3: Write this code :

func scrollViewDidScroll(_ scrollView: UIScrollView) {


if isGetResponse {
    if (scrollView.contentOffset.y == scrollView.contentSize.height - scrollView.frame.size.height)
    {
        if totalArrayCount! > self.arrProductListing.count{

                isGetResponse = false
                activityIndiator?.startAnimating()
                self.view.bringSubview(toFront: activityIndiator!)
                pageIndex = pageIndex + 1
                print(pageIndex)
                self.getProductListing(withPageCount: pageIndex)
            }
        }

        //LOAD MORE
        // you can also add a isLoading bool value for better dealing :D
    }
}

In service call you can send the page index and from the server end they send back the response.

Thank you.



回答5:

I used that code while doing pagination. The point is; catching the loaded cell index while collection view is loading and control it's mod with a number and fetch datas seperately with page size field in the api (if there is). You can decide which number will be smaller than this calculation and you will control it.

For example you fetched 5 datas and loaded it and, if this state is ok, you will fetch the other 5. Here is the sample code for that.

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if let vc = self.parentViewController as? SellController {
            if vc.dontFetch == false {
                DispatchQueue.main.async {
                    if self.salesData.count > 3 {
                        if indexPath.row != 1 {
                            if indexPath.row % 3 == 1 {
                                print("indexpath: \(indexPath.row)")
                                vc.pagination += 1
                                vc.reload()

                            }
                        }
                    }
                }
            }
        }
    }

In this code i am controlling indexpath.row % 3 == 1 or not. It can be little bit complex so i can share a code block if you want. Good luck:)



回答6:

-- itemList - your data array.

-- pageCount - variable used to keep track of the number of pages.

-- totalCount - total number of data

--- append data to itemList every time you call the API.

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if indexPath.row == itemList.count - 1 && itemList.count < totalCount{
        pageCount += 1
        // Call API here
    }
}


回答7:

Easy way to do that

 var page: Int = 0
 var isPageRefreshing:Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    YourApi(page1: 0)
}

 func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if(self.mycollectionview.contentOffset.y >= (self.mycollectionview.contentSize.height - self.mycollectionview.bounds.size.height)) {
        if !isPageRefreshing {
            isPageRefreshing = true
            print(page)
            page = page + 1
            YourApi(page1: page)
        }
    }
}

In your api methods

func YourApi(page1: Int) {
    let mypage = String(page1)
    let request: String = String.init(format:"apiName/%@", mypage)
    print(request)
}

That's it.



回答8:

The code in willDisplay cell method calls load more function while your scroll is 5 cells away from the end. While fetching data show loader in collection view footer. Hide footer when loading is completed.

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {        
        let currentPage = collectionView.contentOffset.y / collectionView.frame.size.width;
        if (aryDataSource.count >= yourAPIResponsebatchCount && aryDataSource.count - indexPath.row == 5 && currentPage >= currentPage && isDataLoading) {
            currentPage++;
            self.fetchMoreData()
        }
        else { }
}