UICollectionView当前可见单元格索引

Irf*_*ISH 104 objective-c ipad ios uicollectionview

UICollectionView在我的iPad应用程序中第一次使用.我设置UICollectionView它的大小和单元格大小相同,意味着一次只显示一次单元格.

问题: 现在当用户滚动UICollectionView我需要知道哪个单元格可见时,我必须更新其他UI元素.我没有找到任何委托方法.我怎样才能做到这一点?

码:

[self.mainImageCollection setTag:MAIN_IMAGE_COLLECTION_VIEW];
[self.mainImageCollection registerClass:[InspirationMainImageCollectionCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
[self.mainImageFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.mainImageFlowLayout setMinimumInteritemSpacing:0.0f];
[self.mainImageFlowLayout setMinimumLineSpacing:0.0f];
self.mainImageFlowLayout.minimumLineSpacing = 0;
[self.mainImageCollection setPagingEnabled:YES];
[self.mainImageCollection setShowsHorizontalScrollIndicator:NO];
[self.mainImageCollection setCollectionViewLayout:self.mainImageFlowLayout];
Run Code Online (Sandbox Code Playgroud)

我尝试过的:

正如UICollectionViewConforms to UIScrollView,当用户滚动以UIScrollViewDelegate方法结束时,我得到了

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
Run Code Online (Sandbox Code Playgroud)

但是在上面的函数里面如何获得当前可见的单元格索引UICollectionView

Ant*_*ony 157

indexPathsForVisibleItems可能适用于大多数情况,但有时它会返回一个包含多个索引路径的数组,并且可能很难搞清楚你想要的那个.在这些情况下,您可以执行以下操作:

CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
Run Code Online (Sandbox Code Playgroud)

当集合视图中的每个项目占据整个屏幕时,这尤其有效.

Swift版本

let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)
Run Code Online (Sandbox Code Playgroud)

  • 我同意,有时indexPathsForVisibleItems返回更多的单元格,即使我们认为不应该有这种情况.您的解决方案很有效. (8认同)
  • 我完全处于这种情况,只有一个修复对我有用(但我的情况是用tableview),我需要更改CGPointMake(CGRectGetMidX(visibleRect),CGRectGetMidY(visibleRect)); for CGPointMake(CGRectGetMidX(visibleRect),CGRectGetMinY(visibleRect)); (2认同)
  • 很好,但是如果单元格之间有空格,那么 `visibleIndexPath` 有时会为零,所以 `if (visibleIndexPath) == nil { let cells = collectionView.visibleCells() letvisibleIndexPath = collectionView.indexPathForCell(cells[0] as !UICollectionViewCell)! 作为 NSIndexPath }` (2认同)

LE *_*ANG 121

方法[collectionView visibleCells]为您提供所需的所有visibleCells数组.当你想要的时候使用它

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    for (UICollectionViewCell *cell in [self.mainImageCollection visibleCells]) {
        NSIndexPath *indexPath = [self.mainImageCollection indexPathForCell:cell];
        NSLog(@"%@",indexPath);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `scrollViewDidScroll:`委托方法在任何滚动完成时提供滚动视图更新(这可能是更好的选择).与`scrollViewDidEndDecelerating:`委托方法相反,该方法仅在滚动视图"*从[大滚动]*停止时查询"(参见UIScrollView标题). (10认同)
  • 从iOS 10开始,它现在也可以直接使用indexPathsForVisibleItems :) (4认同)
  • IIRC,`..DidScroll` 被多次调用,即使在短滚动期间也是如此。可能是也可能不是一件好事,这取决于人们想做什么。 (3认同)

Sam*_*ing 70

在Swift 2.2中结合使用的工作答案:

 func scrollViewDidEndDecelerating(scrollView: UIScrollView) {

        var visibleRect = CGRect()

        visibleRect.origin = self.collectionView.contentOffset
        visibleRect.size = self.collectionView.bounds.size

        let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))

        let visibleIndexPath: NSIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)

        guard let indexPath = visibleIndexPath else { return } 
        print(indexPath)

    }
Run Code Online (Sandbox Code Playgroud)

Swift 3和Swift 4:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    var visibleRect = CGRect()

    visibleRect.origin = collectionView.contentOffset
    visibleRect.size = collectionView.bounds.size

    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)

    guard let indexPath = collectionView.indexPathForItem(at: visiblePoint) else { return } 

    print(indexPath)
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*hop 18

为了完整起见,这是最终为我工作的方法.它是@Anthony和@ iAn方法的结合.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
      CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
      CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
      NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
      NSLog(@"%@",visibleIndexPath);
}
Run Code Online (Sandbox Code Playgroud)


Mr *_*nev 10

最好使用UICollectionViewDelegate方法:( Swift 3)

// Called before the cell is displayed    
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    print(indexPath.row)
}

// Called when the cell is displayed
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    print(indexPath.row)
}
Run Code Online (Sandbox Code Playgroud)

  • 关于`didEndDisplaying`,来自docs:**告诉委托者指定的单元格已从集合视图中删除.使用此方法可以检测何时从集合视图中删除单元格,而不是监视视图本身以查看它何时消失.**所以我不认为在显示单元格时会调用`didEndDisplaying`. (3认同)

use*_*951 9

只是想为其他人添加:出于某种原因,当我使用pagingEnabled 滚动到collectionView中的上一个单元格时,我没有得到用户可见的单元格.

所以我在dispatch_async中插入代码给它一些"空气",这对我有用.

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    dispatch_async(dispatch_get_main_queue(), ^{
            UICollectionViewCell * visibleCell= [[self.collectionView visibleCells] objectAtIndex:0];


            [visibleCell doSomthing];
        });
}
Run Code Online (Sandbox Code Playgroud)


Mih*_*ari 9

UICollectionView 当前可见单元格索引:Swift 3、4 和 5+

var visibleCurrentCellIndexPath: IndexPath? {
    for cell in self.collectionView.visibleCells {
        let indexPath = self.collectionView.indexPath(for: cell)
        return indexPath
     }
        
     return nil
}
Run Code Online (Sandbox Code Playgroud)

作为扩展:

extension UICollectionView {
  var visibleCurrentCellIndexPath: IndexPath? {
    for cell in self.visibleCells {
      let indexPath = self.indexPath(for: cell)
      return indexPath
    }
    
    return nil
  }
}
Run Code Online (Sandbox Code Playgroud)

用法:

if let indexPath = collectionView.visibleCurrentCellIndexPath { 
   /// do something
}
Run Code Online (Sandbox Code Playgroud)


Hir*_*hal 7

对于Swift 3.0

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let visibleRect = CGRect(origin: colView.contentOffset, size: colView.bounds.size)
    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
    let indexPath = colView.indexPathForItem(at: visiblePoint)
}
Run Code Online (Sandbox Code Playgroud)


Ani*_*eja 6

Swift 3.0

最简单的解决方案,它将为您提供可视单元格的indexPath.

yourCollectionView.indexPathsForVisibleItems 
Run Code Online (Sandbox Code Playgroud)

将返回indexpath数组.

只需从数组中取出第一个对象.

yourCollectionView.indexPathsForVisibleItems.first
Run Code Online (Sandbox Code Playgroud)

我想它也应该与Objective-C一起使用.