10

I started building a TableView in my app by using a TableViewController in a storyboard. When you do this, you have a very cool effect when you scroll down your list : the cells moving behind the nav bar get blurred.

Some time later, I had to move from this TableViewController to a ViewController with a TableView inside (I had to add other views at the bottom of the table).

In order to avoid having the first cells hidden by the navigation bar (being over it), I added constraints to the Top and Bottom Layout Guides, and to the left and right edges of the view.

This works fine, but I lost the cool blurred scrolling effect : the cells seem to be disappearing before going behind the navigation bar.

I've seen workarounds with people not using constraints and putting magic numbers in interface builder. I cannot do this, first because I dislike it, and second because I have to be iOS 6 compatible.

What did I miss to be able to benefit again from the blurred navigation bar effect ?

ldavin
  • 423
  • 2
  • 5
  • 16
  • Are you still having this problem? I did the exact thing as you as part of transitioning my app to ios7 (replacing a uitableviewcontroller with a uiviewcontroller), adding a uitableview to it. The uitableview is aligned all the way to the top of the view, and the prototype content is automatically pushed down by the navigation bar in interface builder. Running the app, the content starts just below the navigation bar, and scrolls up under it when scrolling, showing through the translucency... – Marius Waldal Oct 27 '13 at 08:49

5 Answers5

11

You have to manually adjust the contentInset of the table view and make sure the table view frame origin is 0, 0. In this way the table view will be below the navigation bar, but there will be some margin between the content and the scroll view edges (the content gets shifted down).

I advise you to use the topLayoutGuide property of the view controller to set the right contentInsets, instead of hard coding 64 (status bar + navigation bar). There's also bottomLayoutGuide, which you should use in case of UITapBars.

Here is some sample code (viewDidLoad should be fine):

// Set edge insets
CGFloat topLayoutGuide = self.topLayoutGuide.length;
tableView.contentInset = UIEdgeInsetsMake(topLayoutGuide, 0, 0, 0);

By the way, this properties of UIViewController might help you (you should not need to change their default values, but I don't know what your view hierarchy is):

  • automaticallyAdjustsScrollViewInsets
  • edgesForExtendedLayout
  • extendedLayoutIncludesOpaqueBars
Alessandro Vendruscolo
  • 14,493
  • 4
  • 32
  • 41
  • This is almost right. topLayoutGuide.length does not include the height of the navigation bar. So I did something like this: `CGFloat topLayoutGuide = self.topLayoutGuide.length + self.tabBarController.navigationController.navigationBar.frame.size.height;` (don't use tabBarController if you don't have it) – Enrico Susatyo Oct 30 '13 at 00:16
  • The documentation says that the `topLayoutGuide` and `bottomLayoutGuide` include the navigation bar and the tab bar. So perhaps you're retrieving the length before the view is loaded? – Alessandro Vendruscolo Oct 31 '13 at 13:57
  • Hmm, my view hierarchy is Navigation Controller -> TabBar Controller -> Table View Controller. Maybe topLayoutGuide did not realise that the table view is inside a navigation controller? – Enrico Susatyo Oct 31 '13 at 21:23
  • I would try to inspect the length of the top layout guide in `viewWillAppear`; at that point it should have a value. Also, if you're using Auto Layout, you can set constraints to the guide using VFL (as you can see http://stackoverflow.com/questions/19174451/creating-auto-layout-constraints-to-toplayoutguide-and-bottomlayoutguide-in-code, I just can't find the example in the official doc) – Alessandro Vendruscolo Nov 02 '13 at 17:37
2

The tableView needs to be full screen. That is underneath the top and bottom bars. Note don't use the top and bottom layout guides as they are used for positioning relative to the bars not underneath.

Then you need to manually set the content inset of the tableview. This sets the initial scroll position to under the top bar.

Something like:

CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
CGFloat h=MIN(statusBarSize.width, statusBarSize.height);
UIEdgeInsets e = UIEdgeInsetsMake(self.navigationController.navigationBar.bounds.size.height + h,
                                             0.0f,
                                             0.0f,
                                             0.0f);

self.tableView.contentInset = e;

Not you get this functionality for free when using a tableView controller and the "Automatically Adjust content inset" settings

railwayparade
  • 5,154
  • 1
  • 39
  • 49
1

UIViewController property edgesForExtendedLayout does the trick. If you are using storyboards just make sure Extended Edges Under Top Bars is on (and it is by default). If you are creating your view controller programmatically try this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.edgesForExtendedLayout = UIRectEdgeAll;
}

And of course, your table view needs to have proper autoresizing mask/layout constraints

dariaa
  • 6,285
  • 4
  • 42
  • 58
  • It does the trick, but the cells suddenly disappear when their last bottom pixel reaches the bottom of the navigation bar, as if they were deallocated because not on the view anymore. Any idea ? Otherwise I'll mark your answer as accepted – ldavin Oct 10 '13 at 16:06
  • Oh, I see, then you should try a different approach: you should set the origin of your table view to be exactly below the status bar and set the corresponding contentInset for your table view. Do you see my point or should I provide some code? – dariaa Oct 10 '13 at 16:11
  • But then wouldn't I have a gap on iOS 6 between the nav bar and the first section header ? – ldavin Oct 10 '13 at 16:15
  • Yes, you will so you will have to wrap this in if statement and only do this for ios 7 – dariaa Oct 10 '13 at 16:59
1

You probably have the coordinates of your tableView not set to (0, 0) to map to those of the viewController.view.frame or viewController.view.bounds. If you have done that, try setting

self.navigationController.navigationBar.translucent = YES;

unspokenblabber
  • 1,567
  • 1
  • 11
  • 19
  • I don't understand how setting the coordinates to anything would help since I use autolayout's constraints ? – ldavin Oct 10 '13 at 15:59
0

edgesForExtendedLayout is not what you want here, as this will limit the table view underneath the navigation bar. In iOS 7, the view controllers uses fullscreen by default, and the property controlling where the tableview content starts is automaticallyAdjustsScrollViewInsets. This should be YES by default, so check if it is somehow set to NO, or try setting it explicitly.

Check this answer for a good explanation on how this works: https://stackoverflow.com/a/19585104/1485715

Community
  • 1
  • 1
Marius Waldal
  • 9,537
  • 4
  • 30
  • 44