UITableViewCell
iOS development
Swift programming
visibility detection
mobile app development

Best way to check if UITableViewCell is completely visible

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A UITableViewCell can be visible, partially visible, or completely visible. If you only check whether the cell's index path appears in indexPathsForVisibleRows, you learn that some portion of it is on screen, but not whether the entire cell is inside the visible bounds. To check complete visibility, compare the cell's frame with the table view's visible rectangle.

Partial Visibility Is Not Enough

This common check answers only whether the row is at least partly visible:

swift
1if let visible = tableView.indexPathsForVisibleRows,
2   visible.contains(indexPath) {
3    print("At least partially visible")
4}

That is useful sometimes, but it does not tell you whether the full cell is inside the table view viewport.

Check the Cell Frame Against the Visible Bounds

A practical full-visibility check looks like this:

swift
1func isCellCompletelyVisible(at indexPath: IndexPath, in tableView: UITableView) -> Bool {
2    let rect = tableView.rectForRow(at: indexPath)
3    return tableView.bounds.contains(rect)
4}

rectForRow(at:) gives the row rectangle in the table view's own coordinate system, which makes it a good fit for comparing against tableView.bounds.

If the bounds fully contain the row rectangle, the cell is completely visible.

Why This Works Better Than Asking for the Cell

You might be tempted to fetch the cell and inspect its frame.

swift
if let cell = tableView.cellForRow(at: indexPath) {
    print(cell.frame)
}

That works only if the cell already exists as a visible cell object. If the row is off-screen, cellForRow(at:) returns nil.

Using rectForRow(at:) is often cleaner because it works from layout information rather than requiring a live cell instance.

Account for Content Insets If Needed

In some layouts, safe-area handling or custom content insets affect what you consider "fully visible." If you need the visible content area rather than raw bounds, compute that rectangle explicitly.

swift
1func visibleRect(of tableView: UITableView) -> CGRect {
2    let insets = tableView.adjustedContentInset
3    return tableView.bounds.inset(by: UIEdgeInsets(top: insets.top, left: 0, bottom: insets.bottom, right: 0))
4}

Then compare the row rect against that adjusted visible area.

Useful in Scroll-Driven UI Logic

Complete visibility checks are handy for:

  • autoplay or pause behavior
  • starting an animation only when the whole cell is on screen
  • analytics for fully viewed content
  • deciding when to trigger more expensive work

The key is using the stricter definition when partial visibility would give the wrong behavior.

Common Pitfalls

The biggest mistake is relying on indexPathsForVisibleRows when the requirement is full visibility rather than partial visibility.

Another mistake is using cellForRow(at:) as if it were a visibility oracle for every row, even though it returns nil for off-screen cells.

A third issue is forgetting about content insets or safe-area adjustments when defining what counts as truly visible in the UI.

Summary

  • 'indexPathsForVisibleRows tells you whether a row is at least partly visible, not fully visible'
  • For complete visibility, compare rectForRow(at:) with the table view's visible bounds
  • 'rectForRow(at:) is often a better basis than requiring a live cell instance'
  • Adjust for content insets if your UI definition of visibility depends on them
  • Use the stricter check only when full visibility actually matters for the feature

Course illustration
Course illustration

All Rights Reserved.