查看当前可见单元格索引

我第一次在我的 iPad 应用程序中使用 UICollectionView。 我已经设置了 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];

我所尝试的:

由于 UICollectionView符合 UIScrollView,我得到了用户滚动结束时的 UIScrollViewDelegate方法

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

但是在上面的函数里面我怎样才能得到当前 UICollectionView的可见细胞指数呢?

176819 次浏览

方法[ CollectionViewisibleCell ]为您提供所需的所有可见单元数组

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

更新到 Swift 5:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
for cell in yourCollectionView.visibleCells {
let indexPath = yourCollectionView.indexPath(for: cell)
print(indexPath)
}
}

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];

当您的集合视图中的每个项目占据整个屏幕时,这种方法尤其有效。

迅速版本

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)

出于完整性的考虑,这是最终为我所用的方法。这是“ 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);
}

您可以使用 scrollViewDidEndDecelerating: 进行此操作

//@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{


for (UICollectionViewCell *cell in [self.collectionView visibleCells]) {
NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
NSUInteger lastIndex = [indexPath indexAtPosition:[indexPath length] - 1];
NSLog(@"visible cell value %d",lastIndex);
}


}

只是想为其他人补充一下: 由于某种原因,当我在使用 pagingEnable 滚动到 CollectionView 中的 上一页单元格时,我没有得到用户可见的单元格。

因此,我将代码插入递送异步中,给它一些“空气” 这对我很有用。

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




[visibleCell doSomthing];
});
}

斯威夫特5:

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

工作答案合并在 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)


}

这是个老问题了,但对我来说..。

- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {


_m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.firstObject].row;
}


- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
_m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.lastObject].row;
}

尝试这个,它工作。(在下面的例子中,我有3个单元格,例如。)

    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))
let visibleIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)
if let v = visibleIndexPath {
switch v.item {
case 0: setImageDescription()
break
case 1: setImageConditions()
break
case 2: setImageResults()
break
default: break
}
}

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
}

作为延伸:

extension UICollectionView {
var visibleCurrentCellIndexPath: IndexPath? {
for cell in self.visibleCells {
let indexPath = self.indexPath(for: cell)
return indexPath
}
    

return nil
}
}

用法:

if let indexPath = collectionView.visibleCurrentCellIndexPath {
/// do something
}

为了 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)
}

把@Anthony 的答案转换成 Swift 3.0对我来说非常有效:

func scrollViewDidScroll(_ scrollView: UIScrollView) {


var visibleRect = CGRect()
visibleRect.origin = yourCollectionView.contentOffset
visibleRect.size = yourCollectionView.bounds.size
let visiblePoint = CGPoint(x: CGFloat(visibleRect.midX), y: CGFloat(visibleRect.midY))
let visibleIndexPath: IndexPath? = yourCollectionView.indexPathForItem(at: visiblePoint)
print("Visible cell's index is : \(visibleIndexPath?.row)!")
}

Swift 3.0

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

yourCollectionView.indexPathsForVisibleItems

将返回 indexpath 的数组。

像这样从数组中取出第一个对象。

yourCollectionView.indexPathsForVisibleItems.first

我想它在 Objective-C 中应该也能正常工作。

最好使用 UICollectionViewCommittee 方法: (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)
}

还要检查这个片段

let isCellVisible = collectionView.visibleCells.map { collectionView.indexPath(for: $0) }.contains(inspectingIndexPath)

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[1])
}

如果要显示实际数字,可以加 + 1

在这个线程中,有这么多的解决方案,工作良好,如果 手机全屏显示,但他们使用集合视图界限和中点的可视化矩形,但有一个简单的解决方案,这个问题

    DispatchQueue.main.async {
let visibleCell = self.collImages.visibleCells.first
print(self.collImages.indexPath(for: visibleCell))
}

通过这个方法,您可以获得可见单元格的 indexPath。我之所以添加 DispatchQueue,是因为当你快速滑动时,如果下一个单元格出现了一小会儿,那么如果没有 dispatchQueue,你将得到短暂显示的单元格的 indexPath,而不是显示在屏幕上的单元格。