Objective c iOS6 UICollectionView和UIPageControl-如何获取可见单元格?

Objective c iOS6 UICollectionView和UIPageControl-如何获取可见单元格?,objective-c,ios,ios6,Objective C,Ios,Ios6,在研究iOS6的新功能时,我遇到了一个问题。 我目前正在使用Flow layout和滚动方向设置为水平、滚动和分页功能对其进行测试。我已经将它的大小设置为与我的自定义单元格完全相同,因此它可以一次显示一个单元格,通过横向滚动,用户可以看到其他现有单元格 它工作得很好 现在我想在我创建的集合视图中添加和,这样它就可以显示哪个单元格是可见的,以及有多少个单元格 构建页面控件非常简单,定义了框架和页面数 我遇到的问题,如问题标题所示,是如何获取集合视图中当前可见的单元格,以便它可以更改页面控件的cur

在研究iOS6的新功能时,我遇到了一个问题。
我目前正在使用Flow layout和滚动方向设置为水平、滚动和分页功能对其进行测试。我已经将它的大小设置为与我的自定义单元格完全相同,因此它可以一次显示一个单元格,通过横向滚动,用户可以看到其他现有单元格

它工作得很好

现在我想在我创建的集合视图中添加和,这样它就可以显示哪个单元格是可见的,以及有多少个单元格

构建页面控件非常简单,定义了框架和页面数

我遇到的问题,如问题标题所示,是如何获取集合视图中当前可见的单元格,以便它可以更改页面控件的currentPage

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
}
我尝试过委托方法,比如cellForItemAtIndexPath,但它是用来加载单元格的,而不是显示它们。didEndDisplayingCell在一个单元格不再显示时触发,这与我需要的相反

对于我来说,-visibleCells和-indexPathsForVisibleItems(集合视图方法)似乎是正确的选择,但我遇到了另一个问题。什么时候触发它们


提前谢谢,希望我说得够清楚,让你们能理解我

我也为此挣扎了一段时间,然后有人建议我查看UICollectionView的父类。其中一个恰好是,如果您将自己设置为,您可以访问非常有用的方法,例如ScrollViewDiEndDecelling,这是更新UIPageControl的好地方。

您必须将自己设置为
UIScrollViewDelegate
并实现
ScrollViewDiEndDecelling:
方法,如下:

 func scrollViewDidScroll(scrollView: UIScrollView) {
   let contentOffset = scrollView.contentOffset
   let centrePoint =  CGPointMake(
    contentOffset.x + CGRectGetMidX(scrollView.frame),
    contentOffset.y + CGRectGetMidY(scrollView.frame)
   )
   if let index = self.collectionView.indexPathForItemAtPoint(centrePoint){
     self.pageControl.currentPage = index.row
   }
 }
目标-C

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    CGFloat pageWidth = self.collectionView.frame.size.width;
    self.pageControl.currentPage = self.collectionView.contentOffset.x / pageWidth;
}
Swift

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

    let pageWidth = self.collectionView.frame.size.width
    pageControl.currentPage = Int(self.collectionView.contentOffset.x / pageWidth)
}

我会推荐一个小调整的计算和处理,因为它将更新页面控制立即在任何滚动位置与更好的准确性

下面的解决方案适用于任何滚动视图或it子类(UITableView UICollectionView和其他)

在viewDidLoad方法中编写

scrollView.delegate = self
然后为您的语言使用代码:

斯威夫特3

func scrollViewDidScroll(_ scrollView: UIScrollView) 
    {
       let pageWidth = scrollView.frame.width
       pageControl.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
    }
Swift 2:

func scrollViewDidScroll(scrollView: UIScrollView) 
{
   let pageWidth = CGRectGetWidth(scrollView.frame)
   pageControl.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
}
目标C

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat pageWidth = self.collectionView.frame.size.width;
    self.pageControl.currentPage = (self.collectionView.contentOffset.x + pageWidth / 2) / pageWidth;
}
  • 将页面控件置于视图中或按代码设置
  • 设置UIScrollViewDelegate
  • 在收集视图中,添加以下内容 用于计算页数的代码
  • 整版 =地板(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width); [pageControl setNumberOfPages:pages]

    添加ScrollView委托的方法

    pragma标记-用于UIPageControl的UIScrollVewDelegate
    代码较少的另一个选项是使用可见项索引路径并设置页面控件

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
        self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
    }
    
    简捷

    public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        pageControl.currentPage = (collectionView.indexPathsForVisibleItems().first?.row)!
    }
    

    如果您实现了
    UICollectionViewDelegate
    ,则已经实现了
    uicrollViewDelegate
    ,我知道这是一个旧的,但我只需要再次实现这种功能,并添加一些内容,以提供更完整的答案

    首先:使用
    ScrollViewDiEndDecreating
    假设用户在拖动时抬起手指(更像是轻弹动作),因此存在减速阶段。如果用户在不抬起手指的情况下拖动,则
    UIPageControl
    仍将指示拖动开始前的旧页面。相反,使用
    scrollViewDidScroll
    回调意味着视图在拖动和轻弹之后以及拖动和滚动期间都会更新,因此用户感觉它的响应性和准确性更高

    其次:依靠
    pagewidth
    计算所选索引时,假设所有单元格的宽度相同,并且每个屏幕有一个单元格。利用
    UICollectionView
    上的
    indexPathForItemAtPoint
    方法,可以获得更具弹性的结果,适用于不同的布局和单元格大小。下面的实现假设帧的中心是要在
    页面控件中表示的所需单元格。此外,如果存在单元格间距,则在滚动期间,selectedIndex可能为零或可选,因此在页面控件上进行设置之前,需要检查并取消包装

     func scrollViewDidScroll(scrollView: UIScrollView) {
       let contentOffset = scrollView.contentOffset
       let centrePoint =  CGPointMake(
        contentOffset.x + CGRectGetMidX(scrollView.frame),
        contentOffset.y + CGRectGetMidY(scrollView.frame)
       )
       if let index = self.collectionView.indexPathForItemAtPoint(centrePoint){
         self.pageControl.currentPage = index.row
       }
     }
    
    还有一件事-使用如下方式设置
    UIPageControl
    上的页数:

      func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        self.pageControl.numberOfPages = 20
        return self.pageControl.numberOfPages
      } 
    

    如果使用
    scrollViewDidScroll
    ,则应手动更新页面控件以⚠️ 点击页面控件时,避免闪烁的点

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
        self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
    }
    
    设置
    ui页面控件

    let pageControl = UIPageControl()
    pageControl.pageIndicatorTintColor = .label
    pageControl.defersCurrentPageDisplay = true // Opt-out from automatic display
    pageControl.numberOfPages = viewModel.items.count
    pageControl.addTarget(self, action: #selector(pageControlValueChanged), for: .valueChanged)
    
    执行操作(使用下面的扩展)

    在每个滚动条上手动更新
    ui页面控件

    extension ViewController: UIScrollViewDelegate {
            
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            pageControl.currentPage = collectionView.currentPage
            pageControl.updateCurrentPageDisplay() // Display only here
        }
    }
    
    
    方便的
    UICollectionView
    扩展

    extension CGRect {
        
        var middle: CGPoint {
            CGPoint(x: midX, y: midY)
        }
    }
    
    extension UICollectionView {
        
        var visibleArea: CGRect {
            CGRect(origin: contentOffset, size: bounds.size)
        }
        
        var currentPage: Int {
            indexPathForItem(at: visibleArea.middle)?.row ?? 0
        }
        
        func scroll(to page: Int) {
            scrollToItem(
                at: IndexPath(row: page, section: 0),
                at: .centeredHorizontally,
                animated: true
            )
        }
    }
    

    无需为CollectionView创建IVAR:
    -(void)ScrollViewDiEndDecelling:(UIScrollView*)scrollView{CGFloat pageWidth=\u tutorialCollectionViewFrame.size.width;\u pageControl.currentPage=scrollView.contentOffset.x/pageWidth;}
    是的正确答案…:func ScrollViewDiEndDecelling(scrollView:UIScrollView){let pageWidth:CGFloat=self.collectionView.frame.size.width self.pageControl.currentPage=Int(self.collectionView.contentOffset.x/pageWidth)}我发现改用scrollViewDidScroll会更流畅,因为理论上你可以在不更新pageControl的情况下左右滚动,直到它停止减速为止。我的代码如下所示:func scrollViewDidScroll(scrollView:UIScrollView){let page=Int(round(self.collectionView.contentOffset.x/self.collectionView.frame.size.width))如果self.pageControl.currentPage!=page{self.pageControl.currentPage=page}我向UIViewController添加了委托b