4

In my iOS 7 app, I have my view set to "extend edges under top bars" so my uitableview has the translucent effect when you scroll it under the navigation bar as you are scrolling down. But when you scroll back to the top, or when it loads, it properly positions the first cell below the nav bar, not underneath it.

The problem is, that indexPathsForVisibleRows sees the cell underneath the nav bar. So for example, if we scroll down so that all we see is cell index 1 (the 2nd cell), cell index 0 is underneath the nav bar and when we call indexPathsForVisibleRows, it returns index 0 instead of index 1 as the lowest cell that is visible.

Any other way around this?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Jesse
  • 2,674
  • 6
  • 30
  • 47
  • What problem is it causing you? Is the cell not actually visible to you? – Wain Dec 12 '13 at 21:22
  • I need to get the index of the top visible cell, the one that we can actually see, not the one that is behind the navigation bar – Jesse Dec 12 '13 at 21:25
  • 1
    The cell under the navbar is visible. It is being displayed behind the navbar. You need a different approach to determine the cell just below the navbar. – rmaddy Dec 12 '13 at 21:28
  • 1
    You may need to implement your own logic based on the cell frames. Take a look at this: http://stackoverflow.com/questions/9831485/best-way-to-check-if-uitableviewcell-is-completely-visible – TotoroTotoro Dec 12 '13 at 21:29
  • 1
    Look at `indexPathsForRowsInRect:` – Wain Dec 12 '13 at 21:30
  • Wain, that may work too, thanks – Jesse Dec 12 '13 at 21:31
  • It indeed may be a bit counter-intuitive when you look at this behaviour in the context of `scrollToRowAtIndexPath:atScrollPosition:animated:`. For instance, `indexPathsForVisibleRows` returns row index 0 even if the corresponding cell is under the navigation bar. But `scrollToRowAtIndexPath` called for row at the same index 0 will display first cell below the navigation bar. I am calling `scrollToRowAtIndexPath` with `UITableViewScrollPositionTop` as the scroll position. – Marcin Czenko Jan 28 '14 at 03:10

2 Answers2

9

One option is to get the y-coordinate of the bottom of the navbar and translate this to the coordinate system of the tableview. Once you have that, you can get the indexPath or cell from the tableview based on that point.

UINavigationBar *navbar = self.navigationController.navigationBar;
CGRect localFrame = [self.tableView convertRect:navbar.bounds fromView:navbar];
CGPoint point = CGPointMake(0, localFrame.origin.y + localFrame.size.height + 1);
NSIndexPath *path = [self.tableView indexPathForRowAtPoint:point];
rmaddy
  • 314,917
  • 42
  • 532
  • 579
2

The Safe Area is the name of the area of the table view that does not contain any translucent bars. Add a category on UITableView to return the rows in the safe area as follows:

UITableView+SafeArea.h

@interface UITableView (SafeArea)

- (NSArray<NSIndexPath *> *)sa_indexPathsForSafeAreaRows;

@end

UITableView+SafeArea.m

@implementation UITableView (SafeArea)

- (NSArray<NSIndexPath *> *)sa_indexPathsForSafeAreaRows{
    return [self indexPathsForRowsInRect:self.safeAreaLayoutGuide.layoutFrame];
}

@end
malhal
  • 26,330
  • 7
  • 115
  • 133