4

How to Find All Fully Visible Cells in Table and Collection View

 1 year ago
source link: https://swiftsenpai.com/development/find-fully-visible-cells/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

How to Find All Fully Visible Cells in Table and Collection View

Imagine you are given a task to find out which table view cells that are currently fully visible on screen. So you fire up Xcode, access the UITableView‘s indexPathsForVisibleRows and expect that to get the job done.

Very soon, you will notice that something is not right. The result you get is a bit off. Cells that are partially visible on screen are also included in the result, and this is not what you want. How should you go about this?

The solution is actually pretty simple, all you need to do is think out of the box. Let me show you how.


Getting the Index Paths for UITableView

In order to find index paths for all fully visible cells, we must first have a way to determine if a cell is completely visible based on its index path.

So what is another way of saying “a cell is fully visible”?

A cell where its content view completely intersects with the table view is considered a fully visible cell.

With that in mind, we translate the above statement into code like so:

let cellFrame = tableView.rectForRow(at: indexPath)
let isCellFullyVisible = tableView.bounds.contains(cellFrame)

Once we are able to determine if a cell is completely visible based on its index path, getting index paths for all fully visible cells has become fairly straightforward.

let visibleIndexPaths = tableView.indexPathsForVisibleRows!
let fullyVisibleIndexPaths = visibleIndexPaths.filter { indexPath in
    // Filter out all the partially visible cells   
    let cellFrame = tableView.rectForRow(at: indexPath)
    let isCellFullyVisible = tableView.bounds.contains(cellFrame)
    return isCellFullyVisible
}

That’s it for table view. Next up, collection view!


Getting the Index Paths for UICollectionView

In terms of the collection view, the general approach is basically the same. However, the collection view works a bit differently from the table view, we can’t get the collection view cells’ frame directly. We must access the cell’s frame via its layout attribute like so:

let layoutAttribute = collectionView.layoutAttributesForItem(at: indexPath)!
let cellFrame = layoutAttribute.frame
let isCellFullyVisible = collectionView.bounds.contains(cellFrame)

The filtering part is basically the same as the table view, just make sure to use indexPathsForVisibleItems instead of  indexPathsForVisibleRows.

let visibleIndexPaths = collectionView.indexPathsForVisibleItems
let fullyVisibleIndexPaths = visibleIndexPaths.filter { indexPath in
    // Filter out all the partially visible cells
    let layoutAttribute = collectionView.layoutAttributesForItem(at: indexPath)!
    let cellFrame = layoutAttribute.frame
    let isCellFullyVisible = collectionView.bounds.contains(cellFrame)
    return isCellFullyVisible
}

Taking One Step Further

As a good developer, we should always strive for writing clean and reusable code. Thus, let’s make the code I just show you an extension of the table view and collection view functionality.

extension UITableView {

    func isCellAtIndexPathFullyVisible(_ indexPath: IndexPath) -> Bool {

        let cellFrame = rectForRow(at: indexPath)
        return bounds.contains(cellFrame)
    }

    func indexPathsForFullyVisibleRows() -> [IndexPath] {

        let visibleIndexPaths = indexPathsForVisibleRows ?? []

        return visibleIndexPaths.filter { indexPath in
            return isCellAtIndexPathFullyVisible(indexPath)
        }
    }
}
extension UICollectionView {

    func isCellAtIndexPathFullyVisible(_ indexPath: IndexPath) -> Bool {

        guard let layoutAttribute = layoutAttributesForItem(at: indexPath) else {
            return false
        }

        let cellFrame = layoutAttribute.frame
        return self.bounds.contains(cellFrame)
    }

    func indexPathsForFullyVisibleItems() -> [IndexPath] {

        let visibleIndexPaths = indexPathsForVisibleItems

        return visibleIndexPaths.filter { indexPath in
            return isCellAtIndexPathFullyVisible(indexPath)
        }
    }
}

With that in place, getting index paths for all fully visible cells has become as simple as:

let fullyVisibleIndexPaths = tableView.indexPathsForFullyVisibleRows()
let fullyVisibleIndexPaths = collectionView.indexPathsForFullyVisibleItems()

Pretty clean isn’t it?


If you enjoy reading this article, feel free to check out my other iOS development related articles. You can also follow me on Twitter, and subscribe to my monthly newsletter so that you won’t miss out on any of my upcoming iOS development-related articles.

Thanks for reading. 👨🏻‍💻



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK