如何在 UICollectionView 中快速添加分页?

Posted

技术标签:

【中文标题】如何在 UICollectionView 中快速添加分页?【英文标题】:How to add pagination in UICollectionView in swift? 【发布时间】:2018-07-11 09:41:58 【问题描述】:

我有一个显示项目的 UICollection 视图。现在我想在 UICollectionView 上添加分页。我不想为此功能使用任何第三方。请告诉我如何实现这一目标!

我有四个一例http://slicode.com/bottom-refresh-control-uicollectionview/

但在此我必须向上拖动滚动视图几秒钟才能使其工作。

【问题讨论】:

检查collectionView contentOffset,如果滚动到达底部则调用下一页。您也可以以编程方式开始刷新 refreshControl。 你能提供一些代码吗? 你的问题解决了吗? 是的,我接受了你的回答。学习这些课程超级简单 【参考方案1】:

简单的方法

 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)
        
    

在您的 api 方法中

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

就是这样。

【讨论】:

【参考方案2】:

如果你想添加底部刷新控件,你必须使用下面的帮助类。

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

下载这两个在 Objective-C 中的文件。您必须在桥接头中导入此文件

#import "UIScrollView+BottomRefreshControl.h"

像这样添加刷新控件。

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

这个帮助类为您提供了新的bottomRefreshControl 属性,它可以帮助您在底部添加刷新控件。

【讨论】:

这里 fetchNextData() 与刷新的关系。应该调用哪个方法 @Techiee 将 #selector(refresh) 替换为 #selector(fetchNextData) 可能对您有用。 我在集合视图中添加了刷新控件作为子视图,但它没有显示在页脚中。它显示为集合视图顶部作为拉刷新 @Techiee 你是只滚动垂直/水平方向还是双向滚动 仅垂直方向【参考方案3】:

我已经在我的一个应用程序中添加了加载更多功能,所以让我给你代码

    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
            

        
    

【讨论】:

如何维护 isLastPageReached ?这个函数用在哪里 self.removeLoadMoreView ? @Techiee 你需要在 api 响应中管理的布尔值。如果两者相同,我得到页面总数和当前页面,那么 bool 将变为 true,否则为 false 这个函数在哪里使用 self.removeLoadMoreView ? - 让我编辑我的答案 请问您定义了哪些常量?例如isLoadMore【参考方案4】:

请试试这个对我有用。

第 1 步:

声明一个全局变量:

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

设置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!)

第 2 步: 在api调用方法中设置值:

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

第 3 步: 写下这段代码:

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
    

在服务调用中,您可以发送页面索引,然后从服务器端返回响应。

谢谢。

【讨论】:

你在哪里定义 totalArrayCountpageIndex 这个解决方案看起来不错,但很混乱 谢谢,对我来说最好使用scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.size.height【参考方案5】:

CollectionView 委托方法:在 CollectionView 上加载更多关于 Scroll Demand 的数据。

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.

【讨论】:

【参考方案6】:

以下两个函数负责分页。如下所示。

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    if current_page < total_page && indexPath.row == cars.count - 1 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "loading_cell", for: indexPath) as! PaginationCollectionViewCell
        cell.actIndicator.startAnimating()

        return cell
    else 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! PaginationCollectionViewCell
        cell.lbTitle.text = cars[indexPath.row].company_name
        cell.lbDescription.text = cars[indexPath.row].engine_power
        return cell
    


override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) 
    if current_page < total_page && indexPath.row == cars.count - 1 
        current_page = current_page + 1
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) 
            self.fetchData(page: self.current_page)
        
    

【讨论】:

【参考方案7】:

我在进行分页时使用了该代码。 重点是;在集合视图加载时捕获加载的单元格索引,并使用数字控制它的 mod,并使用 api 中的页面大小字段单独获取数据(如果有)。您可以决定哪个数字将小于此计算,并且您将控制它。

例如,您获取了 5 个数据并加载了它,如果此状态正常,您将获取其他 5 个。这是示例代码。

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

                            
                        
                    
                
            
        
    

在这段代码中,我控制 indexpath.row % 3 == 1 与否。它可能有点复杂,所以如果你愿意,我可以分享一个代码块。祝你好运:)

【讨论】:

【参考方案8】:

-- itemList - 你的数据数组。

-- pageCount - 用于跟踪页数的变量。

-- totalCount - 数据总数

--- 每次调用 API 时将数据附加到 itemList

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

【讨论】:

【参考方案9】:

willDisplay cell 方法中的代码调用 load more 函数,而您的滚动条距离末端 5 个单元格。获取数据时在集合视图页脚中显示加载程序。加载完成后隐藏页脚。

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  

【讨论】:

以上是关于如何在 UICollectionView 中快速添加分页?的主要内容,如果未能解决你的问题,请参考以下文章

如何快速从 UICollectionView 中的 UIView 中删除焦点阴影?

如何快速获取两个 UICollectionView 的 ScrollView?

如何在我的 iOS 应用程序中添加一项权利,以便在请求 Apple 之前快速测试它是不是有效

快速,如何使用 UICollectionView

如何以编程方式快速创建 uicollectionview(没有情节提要)

如何在绘图快速条形图中添加一条线