Why is there extra padding at the top of my UITableView with style UITableViewStyleGrouped in iOS7

http://stackoverflow.com/questions/18880341/why-is-there-extra-padding-at-the-top-of-my-uitableview-with-style-uitableviewst


up vote 288 down vote

I was helped by the following:

YouStoryboard.storyboard > YouViewController > Attributes inspector > Uncheck - Adjust scroll view insets.

share improve this answer
 
2  
Thanks. This one helped me. –  palme  Nov 12 '13 at 12:49
21  
I think this is the correct way of removing that padding, instead of tampering with edgeInset values. –  Hgeg Nov 24 '13 at 17:18 
7  
This didn't work for me -- I have an opaque navBar above and this turned off pushes the content under it. –  slycrel  Jan 7 '14 at 18:08
2  
Not working as said by slycrel –  Aqib Mumtaz  Apr 29 '14 at 10:30
2  
Does not work when using custom collectionview. (When tableview is insidecollectionviewcell) –  Akshit Zaveri  Jul 27 '14 at 12:16
Amsterdam, Netherlands
Work at  Booking.com
  • Senior Machine Learning Scientist, Personalization
    pythonhadoop
  • iOS Developer
    ioscocoa
up vote 164 down vote

I played around with it a bit more and it seems like this is a side-effect of setting the tableView's tableHeaderView = nil.

Because my tableView has a dynamically appearing tableHeaderView, when I need to hide the tableHeaderView, instead of doing self.tableView.tableHeaderView = nil;, I do:

self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width, 0.01f)];

I like this solution better than setting a somewhat arbitrary contentInset.top because I use the contentInset.top dynamically as well. Having to remember to remove an extra 35px whenever I recalculate contentInset.top is tedious.

share improve this answer
 
4  
Great solution! Indeed, you have to set it to 0.01f to get rid of the default table view header view as in your code. –  Simone Manganelli  Sep 27 '13 at 23:16
3  
it worked for me.... –  Leena  Oct 22 '13 at 11:48
2  
BTW, this is also possible to do with one drag & drop in the Interface Builder. Anyway, thanks! :) –  Rudolf Adamkovic  Nov 7 '13 at 16:31
5  
you sir deserves a medal for this –  Vaibhav Gautam  Nov 18 '13 at 8:30
4  
Bear in mind that a 0.01f height view at the top of your table view will mean all the cells beaneath are misaligned (first cell with have a Y origin of 0.01, the next of cell_height+0.01, etc) so the contents of those cells will be misaligned. (Turn on Debug > Color Misaligned Images in the simulator to see this for yourself.) You don't want to do that. –  Simon Whitaker  Apr 25 '14 at 11:19 
up vote 77 down vote

Try changing the contentInset property that UITableView inherits from UIScrollView.

self.tableView.contentInset = UIEdgeInsetsMake(-36, 0, 0, 0);

It's a workaround, but it works

share improve this answer
 
1  
contentTableView.contentInset = UIEdgeInsetsMake(-20, 0, -20, 0); worked best for me because there were 20 extra pixels at the top and bottom. –  Brian  Jan 16 '14 at 19:31
 
Thanks! It works for me also. –  Jack Dawson  Jan 21 '14 at 10:02
 
Although this "brute force" solution works, I think the bottom ones (specifically the automatically adjust insets) should be ranked higher. –  eladleb  Apr 2 '14 at 13:37
 
Finally... Thanks for the Workaround, works better than every Delegate method I Tried ;-) –  Hernan Arber  Oct 5 '14 at 10:43
 
this should be the accepted answer .. –  Mohammad Zekrallah  Oct 13 at 14:27
up vote 76 down vote
   self.automaticallyAdjustsScrollViewInsets = NO;

try , you can deal with it!

share improve this answer
 
1  
This is it! works like charm. –  Mhdali  Oct 30 '13 at 8:56
1  
Surprisingly, this works. –  Brody Robertson  Nov 6 '13 at 22:11
1  
WORKS!!! Thank you for this answer! –  Vision  Nov 22 '13 at 20:39
1  
1 up for the answer ... thanks man –  Ramiz Girach  Dec 18 '13 at 5:28
3  
This doesn't work if you use a tableHeaderView, it hides it. –  malhal  Dec 27 '13 at 17:10
up vote 67 down vote

For IOS 7 if you are allocing a tableview in a view controller you may look into

self.edgesForExtendedLayout = UIRectEdgeNone;

your problem seemed similar to mine

share improve this answer
 
3  
This fixed the issue I was having, thanks! –  adamweeks  Sep 21 '13 at 22:07
9  
Didn't work for me. –  capikaw  Oct 6 '13 at 13:56
2  
Fixed it for me. Thanks! –  Dasha Salo  Oct 18 '13 at 3:28
1  
YOU ARE AWESOME! –  myusuf3  Dec 29 '13 at 7:26
1  
This worked for me. In swift, the code is self.edgesForExtendedLayout = UIRectEdge.None –  Edward Ford  Mar 28 at 23:21 
up vote 31 down vote

You could detect if your app is running iOS7 or greater and add this two methods in your table view delegate (usually in your UIViewController code)

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 0.001;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    return 0.001;
}

This maybe is not an elegant solution but works for me

share improve this answer
 
 
This worked for me. UITableView adds space on top for lots of different reasons. Specifically, related to OP, the problem only happens for grouped style table view. And this solution fixed the problem. –  RajV  Oct 28 '13 at 18:18
 
This worked for me too! Hacky but effective... –  horseshoe7  Dec 3 '13 at 10:33
3  
You can use CGFLOAT_MIN instead of 0.001 it gives you the smallest absolute value of CGFloat. –  eiKatte Sep 11 at 9:07
up vote 28 down vote

According to this transition guide for iOS7 by Apple, the scroll view’s content insets is automatically adjusted. The default value of automaticallyAdjustsScrollViewInsets is set to YES.

The UIViewController which has the UITableView should set this property to NO.

self.automaticallyAdjustsScrollViewInsets = NO;

This will do the trick.

EDIT 1:

Also, one could try -

self.navigationController.navigationBar.translucent = YES;

This also removes the extra padding on the top.

share improve this answer
 
 
Very good answer, unless it don't exactly answer the question. Esilver talks about 35px gap, but iOS7 adds extra 20px header: equal to the status bar height. –  Martin  Feb 28 '14 at 10:37
 
Ridiculous problem. Thanks for the answer. –  Gomfucius  Apr 21 '14 at 21:26
 
This is the answer to a different problem. –  entonio  Nov 9 '14 at 4:09
up vote 27 down vote accepted

I have found the cause of my original bug and created a sample project showcasing it. I believe there is an iOS7 bug.

As of iOS7, if you create a UITableView with the Grouped style, but do not have a delegate set on first layout, then you set a delegate and call reloadData, there will be a 35px space at the top that will never go away.

See this project I made showcasing the bug:https://github.com/esilverberg/TableViewDelayedDelegateBug

Specifically this file:https://github.com/esilverberg/TableViewDelayedDelegateBug/blob/master/TableViewDelayedDelegateBug/ViewController.m

If line 24 is active,

[self performSelector:@selector(updateDelegate) withObject:nil afterDelay:0.0];

there will be an extra 35 px space at the top. If line 27 is active and 24 is commented out,

self.tableView.delegate = self;

no space at the top. It's like the tableView is caching a result somewhere and not redrawing itself after the delegate is set and reloadData is called.

share improve this answer
 
16  
I'd add that even if there is a delegate but the delegate's tableView:heightForHeaderInSection:and tableView:heightForFooterInSection: returns 0 you will also have this problem. Implementing the protocol methods above AND returning 0.01f fixed it for me. –  John Estropia  Oct 7 '13 at 5:25
1  
YES!! I've tried 3 so called solutions, and this was the one! Brilliant, thanks :D –  Henrik Erlandsson  Oct 8 '13 at 8:43
 
Helped me a lot :) –  Martin  Nov 1 '13 at 10:58
 
perfect. Anyone reported a bug because I think this is not the intended behaviour. –  zala  Dec 2 '14 at 5:49
 
great find! This is still happening in ios 9 (we're not using XIBs) but setting the delegate on init fixed the spacing (not in loadView or viewDIdLoad). Thank you! –  John Stricker  Oct 22 at 12:32
up vote 21 down vote

Another quick comment... even in XCode 6.1, there is a bug with vertical spaces appearing at the top of UIScrollViewsUITextViews and UITableViews.

Sometimes, the only way to fix this issue is to go into the Storyboard and drag the problem control so it's no longer the first subview on the page.

(My thanks to Oded for pointing me in this direction... I'm posting this comment, just to add a few screenshots, to demonstrate the symptoms and fix.)

share improve this answer
 
1  
Note that this bug, errrr, issue also happens in iOS 8 if you have a UITextView as the first sub-control on your page... so it's not just a UITableView issue. –  Mike Gledhill  Jan 29 at 9:13
 
Great finding.. –  teapeng  Feb 15 at 10:59
 
I was having this problem even in iOS 8.3 and Xcode 6.3. My tableview began with a content offset of -20px. I solved it by following your advice and adding a blank UIView below the tableview as such: UIView *blankView = [[UIView alloc] initWithFrame:self.view.bounds]; blankView.backgroundColor = self.view.backgroundColor; [self.view addSubview:blankView]; self.tableView = [UITableView alloc] init.... etc. –  Jack Dewhurst  Apr 25 at 15:00 
1  
Out of all solution only this hack worked for me. A weird fix to a weird bug. I've faced this issue with UITableview. –  Mesbah  Jun 16 at 8:25 
2  
1 million thank you's! This is the only solution which worked for me. –  user139816  Aug 12 at 11:58
up vote 20 down vote

Storyboard:

Just uncheck: Adjust Scroll View Insets in View Controller's options

Code:

self.automaticallyAdjustsScrollViewInsets = false
share improve this answer
 
 
That didn't work for me –  Radu  Aug 9 at 19:44
 
That works perfectly. Smooth as silk. Thx. –  Oleg Popov  Sep 23 at 8:06
up vote 16 down vote

While using grouped TableView use this to avoid border cutting in viewWillAppear

self.tableView.contentInset = UIEdgeInsetsMake(-35, 0, 0, 0);
share improve this answer
 
up vote 14 down vote

In my case this was what helped me. I'm supporting ios6 also.

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
    self.edgesForExtendedLayout = UIRectEdgeNone;
    self.extendedLayoutIncludesOpaqueBars = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;
}
share improve this answer
 
 
Not sure what this does but it worked perfectly. Could you give some explanation? –  Matt Wolfe  Sep 26 '13 at 18:22
 
@MattWolfe I was lost, and found this solution, not sure either why this is happening. My guess is that controller is deciding that tableview needs an inset, because of the status bar(or in other cases toolbar/tabbar) so it automatically adds it. I'm really struggling with some of the new iOS7 "features". Maybe some one understands it, and has a real explanation on this? –  Lukas  Sep 27 '13 at 7:54
 
Spent the last 2 days porting a relatively small app to iOS 7 and still having minor issues.. I fix it in ios 7 it breaks in 6 and vice versa.. Driving me nuts! –  Matt Wolfe  Sep 27 '13 at 8:08
 
This is a different problem than OP. Even with this, for grouped table view, an extra space is added on the top. –  RajV  Oct 28 '13 at 18:15
1  
this seems to be the key line: self.automaticallyAdjustsScrollViewInsets = NO; just setting that removed the extra space I had. –  Mike M  Oct 31 '13 at 13:12
up vote 11 down vote

Simply add the following to your viewDidLoad in your VC:

self.automaticallyAdjustsScrollViewInsets = NO;
share improve this answer
 
up vote 9 down vote

Swift: iOS I had tableview on scroll view .. when I was click "Back" on the same screen. Scroll view take more space on top.. to solve this I have used :

 self.automaticallyAdjustsScrollViewInsets = false

A Boolean value that indicates whether the view controller should automatically adjust its scroll view insets. Default value is true, which allows the view controller to adjust its scroll view insets in response to the screen areas consumed by the status bar, navigation bar, and toolbar or tab bar. Set to false if you want to manage scroll view inset adjustments yourself, such as when there is more than one scroll view in the view hierarchy.

share improve this answer
 
up vote 7 down vote

I had the same fix as arielyz. Once I moved the UITableView to be not the first subview of the parent view, it went away. My space was 20 px, not 35.

I wasn't able to recreate it in a portrait xib, only a landscape xib. I'll file a radar bug later if I can reproduce it in a simple demo app.

share improve this answer
 
 
Ran into the same issue, wasn't able to solve it by changing the contentInset but this method worked, even though it's pretty hacky. For what it's worth, using the visual debugging tool, I was able to see that while the UITableView had the right height, the UITableViewWrapper inside it did not. –  Michael Fok  Nov 12 '14 at 8:12
 
Perfect. This fixed the bug for me, in XCode 6.1. None of the other suggestions in this StackOverflow page made any difference. I had a UITableView within a UIView, and it WAS the first subview. Dragging it to become the 2nd subview fixed it perfectly. (If anyone needs me, I'll be in the pub.) –  Mike Gledhill  Dec 10 '14 at 13:50 
 
Thank you! This also works if you have a table view controller within a container. Moving the container so that its not the first in the parent's view removes the gap at the top of the table view. –  strangeluck  Jan 21 at 18:49
up vote 6 down vote

A lot of the previous answers above are too hacky. They would break at anytime in the future if Apple decides to fix this unexpected behavior.

Root of the issue:

  1. UITableView doesn't like to have a header with a height of 0.0. If what's you're trying to do is to have a header with a height of 0, you can jump to the solution.

  2. even if later you assign a non 0.0 height to your header, a UITableView doesn't like to be assigned a header with a height of 0.0 at first.

Solution:

Then, the most simple and reliable fix is to ensure that your header height is not 0 when you assign it to your table view.

Something like this would work:

// Replace UIView with whatever class you're using as your header below:
UIView *tableViewHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.tableView.bounds.size.width, CGFLOAT_MIN)];
self.tableView.tableHeaderView = tableViewHeaderView;

Something like this would lead to the issue at some point (typically, after a scroll):

// Replace UIView with whatever class you're using as your header below:
UIView *tableViewHeaderView = [[UIView alloc] initWithFrame:CGRectZero];
self.tableView.tableHeaderView = tableViewHeaderView;
share improve this answer
 
up vote 4 down vote

I've been banging my head against this one as well. Pretty sure this is an iOS7 bug. What helped me eventually, is the order of views in the xib. I had one view in which table view was displayed correctly, and another in which the table view had that extra 35px space. The only difference between then (UITableView wise), is that in the bad-displaying view UITableView was the first child, whereas in the view which was displaying correctly, it was the second.

That did the trick for me, just changing the order of views. I really prefer not to add extra lines of code for a workaround...

share improve this answer
 
 
After trying all the other solutions here, the only thing that worked in my case was to change the order of the subview placement, as you suggested. –  Herman Schaaf  Nov 3 '14 at 10:44
up vote 4 down vote

I think making UIEdgeInsets -35 0 0 0 is tedious. In my case, I implemented tableView: heightForHeaderInSection: method and it has a potential to return 0.

When I changed 0 to 0.1f, the problem just went away.

share improve this answer
 
1  
If I could, I would upvote this more than once. Must be a weird autolayout glitch or something... As anything > 0 works, I suggest instead of 0.1 use FLT_EPSILON or DBL_EPSILON, seeing as both represent the smalles positive value such that 1.0 + epsilon != 1.0 –  Henri Normak  Aug 13 '14 at 2:16
up vote 2 down vote

I'm assuming that is just part of the new UITableViewStyleGrouped styling. It is in all grouped table views and there doesn't seem to be any direct way to control that space.

If that space is being represented by a UIView, it would be possible to search through all the subviews of the UITableView to find that specific view and edit it directly. However, there is also the possibility that that space is just a hardcoded offset before headers and cells start and there won't be any way to edit it.

To search through all subviews (I would run this code when the table has no cells, to make it a little easier to read the output):

- (void)listSubviewsOfView:(UIView *)view {

    // Get the subviews of the view
    NSArray *subviews = [view subviews];

    // Return if there are no subviews
    if ([subviews count] == 0) return;

    for (UIView *subview in subviews) {

        NSLog(@"%@", subview);

        // List the subviews of subview
        [self listSubviewsOfView:subview];
    }
}
share improve this answer
 
3  
If UITableViews (to be more specific UITableViewCellScrollView) on iOS7 have taught us one thing, it's to leave the view hierarchy of built in classes alone. –  Matthias Bauch  Sep 18 '13 at 20:23
 
Good point. The other option is... to keep hacking for each iOS ;) –  Yar  Sep 18 '13 at 20:28
 
Whoops, yeah. Meant to write that warning but forgot. –  Kevin  Sep 19 '13 at 1:46
 
Kevin - I think you are right, this is by design. It appears that returning 0 for heightForHeaderInSection is the easiest way to remove this padding. For some reason on that particular instance it wasn't working for me, but it does work on other UITableViews. –  esilver  Sep 19 '13 at 3:46
 
It's definitely "by design". If you paused execution and ran: po [((UIApplication *)UIApplication.sharedApplication).keyWindow recursiveDescription] you'll see that the table header, or first section header, or first cell (depending on what you use) naturally leaves a 35px border.... boo. –  Mr. T  Sep 21 '13 at 6:54
up vote 2 down vote

I have just removed UITableView from Interface Buildercreated it once again and strange 35px gone away.

It seems that it there is a strange bug in Interface Builder.

share improve this answer
 
 
Strange, this worked for me also. Xcode 6.4 –  P1X3L5  Aug 19 at 15:14 
up vote 1 down vote

I noticed there are many answers to this question depending on what you're trying to do, so I'd share mine in case anyone is going for something the same effect:

In my view controller, I have a grouped UITableView whose tableHeaderView is composed of a 200-point tall UIScrollView, and a single attributed UILabel that contains an ad title, price, location, and time posted. Below it are the contents of the table view.

With the default dimensions of a grouped table view header, the "MORE INFO" header is too far below the "5 days ago" label. I fixed it (already the above image) by overriding the heights for the header and footer of each section.

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return section == kMoreInfoSection ? 33 : UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return UITableViewAutomaticDimension;
}

I learned about overriding the heights from @erurainon's comment in the accepted answer, and UITableViewAutomaticDimension from http://stackoverflow.com/a/14404104/855680. I didn't have to set self.automaticallyAdjustsScrollViewInsets to NO in my view controller unlike what the accepted answer suggests.

I also already tried setting the UIEdgeInsets and giving the table view a negative value for the top, but it didn't work--the entire table view moves up, including the tableHeaderView.

share improve this answer
 
up vote 1 down vote

Just pin your tableview (or make it begin) at the absolute top of the view. The additional unwanted space is exactly the height of a navigation bar.

share improve this answer
 
up vote 1 down vote

Doing below (Swift) solves the problem, but this works when you don't need a header.

func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat.min
}

If you do, you'll have to abandon the very first section and use other for content.

UITableViewDataSource implementation:

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return +1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // the first section we don't use for data
    if section == 0 {
        return 0
    }

    // starting from 1, there are sections we use
    if section == 1 { 
        let dataSection = section - 1

        // use dataSection for your content (useful, when data provided by fetched result controller). For example:
       if let sectionInfo = myFRC!.sections![dataSection] as? NSFetchedResultsSectionInfo {
            return sectionInfo.numberOfObjects
        }
    }

    return 0
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let dataIndexPath = NSIndexPath(forRow: indexPath.row, inSection: (indexPath.section - 1) )
    // return cell using transformed dataIndexPath
}

func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if section == 1 {
        // return your header height
    }
    return CGFloat.min
}


func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 1 {
        // return your header view
    }
    return nil
}

func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    // in my case, even when 1st section header was of zero heigh, I saw the space, an that was a footer. I did not need footer at all, so always gave zero height
    return CGFloat.min
}

And that's it. Model does not know anything about the change, because we transforms the section number upon accessing the data.

share improve this answer
 
up vote 0 down vote

in iOS 7 you view starts a the of the screen instead of beneath the navBar. its vry simple to set that to the bottom of ur navbar. Check THIS answer for the solution, its not the same question but very related to yours.

share improve this answer
 
up vote 0 down vote

use this one i think this help...

 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
 {
    return 0.005f;// set this according to that you want...
 }
share improve this answer
 

你可能感兴趣的:(IOS)