检查 indexPath 处的单元格在屏幕 UICollectionView 上是否可见

Check whether cell at indexPath is visible on screen UICollectionView

我有一个 CollectionView 可以向用户显示图像。我在后台下载这些,下载完成后我调用以下函数来更新 collectionViewCell 并显示图像。

func handlePhotoDownloadCompletion(notification : NSNotification) {
    let userInfo:Dictionary<String,String!> = notification.userInfo as! Dictionary<String,String!>
    let id = userInfo["id"]
    let index = users_cities.indexOf({[=10=].id == id})
    if index != nil {
        let indexPath = NSIndexPath(forRow: index!, inSection: 0)
        let cell = followedCollectionView.cellForItemAtIndexPath(indexPath) as! FeaturedCitiesCollectionViewCell
        if (users_cities[index!].image != nil) {
            cell.backgroundImageView.image = users_cities[index!].image!
        }
    }
}

如果单元格当前在屏幕上可见,这会很好用,但如果不是,我会得到一个 fatal error: unexpectedly found nil while unwrapping an Optional value 以下行出错:

 let cell = followedCollectionView.cellForItemAtIndexPath(indexPath) as! FeaturedCitiesCollectionViewCell

现在,如果 collectionViewCell 尚不可见,甚至不需要调用此函数,因为在这种情况下,图像将在 cellForItemAtIndexPath 方法中设置。

因此我的问题是,如何更改此函数以检查我们正在处理的单元格当前是否可见。我知道 collectionView.visibleCells() 但是,我不确定如何在此处应用它。

获取当前可用单元格

// get visible cells 
let visibleIndexPaths = followedCollectionView.indexPathsForVisibleItems

然后在对单元格进行任何操作之前检查 indexPath 是否包含在 visibleIndexPaths 数组中。

您可以简单地使用 if collectionView.cellForItem(at: indexPath) == nil { }。 collectionView 只会 return 一个可见的单元格。

或者根据您的情况具体更改:

let cell = followedCollectionView.cellForItemAtIndexPath(indexPath) as! FeaturedCitiesCollectionViewCell

至:

if let cell = followedCollectionView.cellForItemAtIndexPath(indexPath) as? FeaturedCitiesCollectionViewCell { }

嵌套的 UICollectionViews 通常需要完全不滚动,因此不会提供任何 contentOffset,因此 iOS 将所有单元格理解为始终可见。那样的话可以参考屏幕边界:

    let cellRect = cell.contentView.convert(cell.contentView.bounds, to: UIScreen.main.coordinateSpace)
    if UIScreen.main.bounds.intersects(cellRect) {
        print("cell is visible")
    }

您可以通过

获取当前索引
// 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)
}

我需要追踪可见的细胞,所以您也可以做类似的事情来更好地追踪您的细胞。

private func configureVisibleIndexPath() {
        let visibleCells = collectionView.indexPathsForVisibleItems
        visibleCells.forEach { indexPath in
            if let cell = collectionView.cellForItem(at: indexPath), collectionView.bounds.contains(cell.frame) {
                print("visible row is \(indexPath.row)"
            }
        }
    }

当您的集合视图配置正确时调用此函数,它还通过在 scrollView 委托中调用它来关注滚动:

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
        configureVisibleIndexPath()
    }
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    configureVisibleIndexPath()
}

是的,我尝试了很多方法,发现这是最好的。

func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
   const currentIndex = (indexPath.row + 1) % (total cell number)
} 

您可以通过以下方式管理可见单元格。

https://github.com/NohEunTae/VisibilityTrackableCollectionView

只需设置检测边界即可:

collectionView.setBoundary(.init(view: someView, mode: .safeArea))