Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check whether cell at indexPath is visible on screen UICollectionView

I have a CollectionView which displays images to the user. I download these in the background, and when the download is complete I call the following func to update the collectionViewCell and display the image.

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

This works great if the cell is currently visible on screen, however if it is not I get a fatal error: unexpectedly found nil while unwrapping an Optional value error on the following line :

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

Now this function does not even need to be called if the collectionViewCell is not yet visible, because in this case the image will be set in the cellForItemAtIndexPath method anyway.

Hence my question, how can I alter this function to check whether the cell we are dealing with is currently visible or not. I know of the collectionView.visibleCells() however, I am not sure how to apply it here.

like image 393
Alk Avatar asked Jul 09 '16 12:07

Alk


People also ask

What is the difference between UITableView and UICollectionView?

For the listing details of each item, people use UITableView because it shows more info on each item. The UICollectionView class manages an ordered collection of data items and presents them using customizable layouts.

How do I get indexPath from cell Swift?

add an 'indexPath` property to the custom table cell. initialize it in cellForRowAtIndexPath. move the tap handler from the view controller to the cell implementation. use the delegation pattern to notify the view controller about the tap event, passing the index path.

What is UICollectionView flow layout?

A layout object that organizes items into a grid with optional header and footer views for each section.


2 Answers

I needed to track cells that are visible so you can also do something like this to track your cells better.

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

Call this function when your collection view is configured properly and it also takes care on scrolling by calling it in scrollView delegates:

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

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    configureVisibleIndexPath()
}
like image 67
Rahul Serodia Avatar answered Sep 21 '22 15:09

Rahul Serodia


Get current available cells

// get visible cells 
let visibleIndexPaths = followedCollectionView.indexPathsForVisibleItems

Then check if your indexPath is contained in the visibleIndexPaths array or not, before doing anything with cells.

like image 37
tuledev Avatar answered Sep 20 '22 15:09

tuledev