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

Posted

技术标签:

【中文标题】检查 indexPath 处的单元格是不是在屏幕 UICollectionView 上可见【英文标题】:Check whether cell at indexPath is visible on screen UICollectionView检查 indexPath 处的单元格是否在屏幕 UICollectionView 上可见 【发布时间】:2016-07-09 12:38:45 【问题描述】:

我有一个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($0.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() 但是,我不确定如何在这里应用它。

【问题讨论】:

【参考方案1】:

获取当前可用的单元格

// get visible cells 
let visibleIndexPaths = followedCollectionView.indexPathsForVisibleItems

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

【讨论】:

indexPathsForVisibleItems 返回错误值,在我的演员表中必须显示 3,4,5,6 但它显示 0,1,2,3【参考方案2】:

嵌套的 UICollectionView 通常根本不需要滚动,因此不会提供 contentOffset,因此 ios 将所有单元格理解为始终可见。在这种情况下,可以将屏幕边界作为参考:

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

【讨论】:

这个方法对于嵌套的 UICollectionViews 来说真的很好。大多数时候,因为我们禁用了嵌套 UICollectionViews 的滚动,因此 visibleIndexPaths 将始终返回所有单元格,即使它们不可见。这个解决方案是我迄今为止在网上找到的最好的解决方案。很棒的一个。【参考方案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)

【讨论】:

【参考方案4】:

我需要跟踪可见的单元格,因此您也可以执行类似的操作来更好地跟踪您的单元格。

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

【讨论】:

【参考方案5】:

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

或者在你的情况下具体改变:

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

到:

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

【讨论】:

【参考方案6】:

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

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

【讨论】:

【参考方案7】:

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

https://github.com/NohEunTae/VisibilityTrackableCollectionView

只需设置要检测的边界:

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

【讨论】:

以上是关于检查 indexPath 处的单元格是不是在屏幕 UICollectionView 上可见的主要内容,如果未能解决你的问题,请参考以下文章

UTableView 当前可见单元格 indexPath.row

可重复使用的单元格为许多单元格重复相同的 indexPath

检查是不是选择了 UITableViewCell,并且单元格离开了屏幕

IndexPath.row 对于静态单元格不是唯一的

如何在 Swift 的自定义单元格中获取值组件的 indexPath?

向下滚动时 UICollectionView 的 indexPath 发生变化