724

Starting in iOS7, there is additional space at the top of my UITableView's which have a style UITableViewStyleGrouped.

Here is an example:

enter image description here

The tableview starts at the first arrow, there are 35 pixels of unexplained padding, then the green header is a UIView returned by viewForHeaderInSection (where the section is 0).

Can anyone explain where this 35-pixel amount is coming from and how I can get rid of it without switching to UITableViewStylePlain?


Update (Answer):

In iOS 11 and later:

tableView.contentInsetAdjustmentBehavior = .never
esilver
  • 27,713
  • 23
  • 122
  • 168
  • are you using the latest iOS 7? Some of these TYPES of inconsistencies (but not all, and perhaps not this one) have been cured during in the later dev previews. I should know: I procrastinated so much some of the problems disappeared. – Dan Rosenstark Sep 18 '13 at 20:14
  • Check answer here - http://stackoverflow.com/a/18986158/1463604 – Nishant May 27 '15 at 12:37
  • Short answer is that this extra padding is probably due to the table view header (not the section header), and that `UITableView` doesn't like to be assigned a header with a height of 0.0. Check http://stackoverflow.com/a/31223403/1394534 for more details. – Aurelien Porte Jul 05 '15 at 13:15
  • 39
    `self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, CGFLOAT_MIN)];` note: `0.0f` is just **ignored** if you use it in the height of the rect. So we use the nearest-to-zero CGFloat possible (at least this "worked" for me... just not ideal solution). – Alejandro Iván Oct 14 '15 at 13:59
  • 2
    @AlejandroIván your comment just made my night. I've got a tableView with grouped prototypes. I'm using numberSections = data.count and setting numberRows = 1. I set a heightForFooterInSection to make a clean space between each and for some reason a blank tableHeaderView appeared. – Ryan Alexander Oct 21 '15 at 05:33
  • Thank you so much! Even though I am using a storyboard, the suggestion from below about unchecking the scroll view inset did not work. – ArdenDev Nov 19 '15 at 16:27
  • You are using **Grouped** UITableView -- you should use **Plain** - This will get rid of the extra padding. – nodebase Oct 25 '16 at 19:54
  • Have you set `tableFooterView` to an empty view? This is a typical hack for plain table views to remove extra empty cells that are added when there are not enough cells to fill the whole screen. In that case, the solution is simple: that hack is not needed for grouped table views, so you can remove it safely and let both `tableHeaderView` and `tableFooterView` set to `nil`. – elitalon Mar 05 '17 at 08:39
  • Seems the problem was fixed since iOS 13. – Míng May 19 '21 at 12:59
  • The root cause of the issue is that before appearing the table view gets header view and its height as a nil for the first section for a some reason , may be even because table view delegate isn't set yet and data source returns nil for `tableView(:titleForHeaderInSection:)` . so easiest way to prevent this issue is to return in data source `numberOfSections(in:)` 0 untill the data is ready so table view won't request header methods of table view delegate and datasource as noticed by @AlejandroIván – Alexander Burdeynyy Jul 06 '21 at 13:46
  • 1
    if #available(iOS 15.0, *) { table.sectionHeaderTopPadding = 0 } Put this code it will work – Vinayak Sep 29 '22 at 06:44

78 Answers78

868

I was helped by the following:

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

enter image description here

Alexander
  • 9,074
  • 2
  • 15
  • 13
  • 42
    I think this is the correct way of removing that padding, instead of tampering with edgeInset values. – Hgeg Nov 24 '13 at 17:18
  • This seems to be the correct way to do it - it removed the space at the top without having to set any edgeInsets or header heights etc. – siburb Nov 25 '13 at 01:18
  • 24
    This didn't work for me -- I have an opaque navBar above and this turned off pushes the content under it. – slycrel Jan 07 '14 at 18:08
  • 5
    Does not work when using custom `collectionview`. (When tableview is inside `collectionviewcell`) – Akshit Zaveri Jul 27 '14 at 12:16
  • This worked great for me for a `UITableView` inside a `UIViewController` (that only takes up the top half of the screen) on iOS 8 – Craig Otis Oct 08 '14 at 17:13
  • 1
    This should be the accepted answer. As to the "why", I have a theory that the "adjust..." works in conjunction with the Extend Edges properties. Meaning that if you allow extending edges under the top bar and you have a scroll view that starts from the top, you probably don't want it's content to be covered by the top bar. So the VC adjusts the insets automatically so that the content goes under the top/bottom bars only when scrolled. Of course this isn't true if the scrollView (tableView) is top-aligned with the top layout guide, not the superview.top. – user3099609 Jan 14 '15 at 12:48
  • 6
    Didn't work for me; Only thing that worked was switching to Plain instead of Grouped – shim Mar 08 '15 at 20:56
  • 2
    Please note this attribute is on the enclosing UIViewController, not on the tableview itself. – CodeBrew May 10 '15 at 21:37
  • 3
    alternativelly with code: `self.automaticallyAdjustsScrollViewInsets = NO;` – andilabs Aug 15 '15 at 10:02
  • This works well for my case, also with an opaque navigationbar. – bio Oct 22 '15 at 15:05
  • This didn't work for me, ironically I have two tableviewControllers being shown from container views. One appears as expected the other has the space annoying as hell – AppHandwerker Oct 23 '15 at 11:18
  • 29
    I had this problem with a TableViewController inside a container view. I had to set this property not directly on the TableViewController which was embedded, but on the view controller which contained the container view. Then it worked. – Andy Mortimer Nov 14 '15 at 12:22
  • Worked fine for me with a tableView inside a UIViewController. – zic10 Dec 04 '15 at 03:36
  • 1
    This worked for one of my original view controllers. The new issue for me was that it was grouped rather than plain – SwiftMatt Jan 18 '16 at 00:41
  • Probably it worked before, but it is not working with Swift / XCode 8.3.2. Check Mr. T's answer. – Borzh Jun 02 '17 at 21:34
  • 2
    `self.automaticallyAdjustsScrollViewInsets = NO.` is the solution. Explanation is here: https://useyourloaf.com/blog/extra-space-when-embedding-table-views/z – Yongxiang Ruan Jun 26 '17 at 16:32
  • 5
    Does this option exist purely to annoy? – Ian Warburton Jul 17 '17 at 17:02
  • @YongxiangRuan : the link is invalid now. I searched 'extra space' keyword in useyourloaf 's archive section. if anyone wants this link search this way. – Tejas Jul 26 '17 at 06:05
  • 1
    I that doesnt work for you, try tableView.contentInset.top = -44 – Shubham Naik Jul 31 '17 at 09:05
  • The issue also happens for an iPhone app on an iPad in iOS 10, where the status bar is at the top and not in the rendered iPhone app portion of the screen. This solution works! – Peter DeWeese Sep 21 '17 at 18:09
  • @AkshitZaveri, I am also facing the same issue(I am having Tableview inside collection view). How you resolved that? – pkc456 Oct 09 '17 at 09:43
  • "Does not work when using custom collectionview. (When tableview is inside collectionviewcell) – Akshit Zaveri Jul 27 '14 at 12:16" Please check solution by "nvrtd frst" below. It worked for me. – Mithun Ravindran Apr 03 '19 at 13:30
  • for me is not working, – Vinayak Jun 13 '22 at 10:11
346

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.

Mr. T
  • 12,795
  • 5
  • 39
  • 47
  • 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
  • 2
    BTW, this is also possible to do with one drag & drop in the Interface Builder. Anyway, thanks! :) – Rudolf Adamkovič Nov 07 '13 at 16:31
  • 9
    you sir deserves a medal for this – Vaibhav Gautam Nov 18 '13 at 08:30
  • 8
    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
  • 1
    I think this is a better solution than setting negative (arbitrary) contentInsets, or turning off scroll view insets. However you do need to make the height of the header view at least 1.f in order for it to work correctly. – cleverbit Sep 05 '14 at 11:43
  • 4
    It's better to use `UITableViewHeaderFooterView` instead of UIView. And `CGFLOAT_MIN` works the same as `0.01f` but better in theory. – Jaybo Feb 14 '15 at 06:47
  • 2
    @SimonWhitaker I see no misalignment with `Color Misaligned Images` for images in cells below a tableHeaderView with height CGFLOAT_MIN on iOS8.4 iPhone 6. – alexkent Jul 09 '15 at 19:23
  • 2
    This works for me while edgesForExtendedLayout didn't work. – xi.lin Aug 01 '15 at 02:55
  • 2
    The other solution (setting self.automaticallyAdjustsScrollViewInsets = false) did not work for me, but this works perfect. Note that it is better to use CGFloat.min or 1.0 (and not 0.01), to avoid misaligned images, as noted above – emem Mar 10 '16 at 15:23
  • 1
    This works for me and I think this is the better solution as it fixed the View directly. Other solutions are applied to the view controller. – Sam Dec 08 '16 at 15:01
  • where to add this? – Rachit Rawat Sep 27 '17 at 11:03
  • 1
    Swift version: self.tableView.tableHeaderView = UIView(frame: CGRect(x:0, y:0, width:self.tableView.bounds.size.width, height:CGFloat.leastNormalMagnitude)) – Phuah Yee Keat Oct 07 '19 at 08:24
  • 2
    @PhuahYeeKeat or could use `CGFloat.leastNonzeroMagnitude` – jarrodparkes Oct 14 '19 at 13:20
194

Try changing the contentInset property that UITableView inherits from UIScrollView.

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

It's a workaround, but it works

YanSte
  • 10,661
  • 3
  • 57
  • 53
nvrtd frst
  • 6,272
  • 4
  • 28
  • 34
  • 7
    `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
  • 1
    Although this "brute force" solution works, I think the bottom ones (specifically the automatically adjust insets) should be ranked higher. – eladleb Apr 02 '14 at 13:37
  • 4
    total hack but iOS is garbage so what can you do. – AlexK Jul 01 '20 at 16:50
180

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

Update:

Swift in iOS 9.x:

self.edgesForExtendedLayout = UIRectEdge.None

Swift 3 :

self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0)
Beslan Tularov
  • 3,111
  • 1
  • 21
  • 34
yeahdixon
  • 6,647
  • 1
  • 41
  • 43
  • 3
    Worked on my plain `UITableView`. The issues stems from the fact my `UITableView` was on a `UIViewController` inside a `UINavigationController` which caused the table content to drop down 44 points so initial content wasn't up behind the `navBar`. That wasn't needed with my layout though, so it just caused issues. Eventually I changed my code to `automaticallyAdjustsScrollViewInsets` which worked also. – DBD Jun 23 '14 at 14:32
  • _This property is applied only to view controllers that are embedded in a container such as UINavigationController. The window’s root view controller does not react to this property. The default value of this property is all._ ..I feel like the default should be 0? Where does this have an advantage. – Desh__ Jun 13 '17 at 21:12
  • 5
    More elegant with Swift 3: `edgesForExtendedLayout = []` – Dave Batton Aug 09 '17 at 22:58
  • Hello @yeahdixon What software do you use to make the pink arrow ? thanks in advance – iArezki Oct 04 '17 at 09:30
140
self.automaticallyAdjustsScrollViewInsets = NO;

try, you can deal with it!

pkamb
  • 33,281
  • 23
  • 160
  • 191
guanhuiwit
  • 1,471
  • 1
  • 8
  • 4
  • This works great to hide the tableHeaderView in iOS 7.0, but it isn't supported in older versions. – Brian Jan 16 '14 at 19:42
  • Works great under iOS 7. – StackRunner Jul 24 '14 at 22:45
  • 4
    Important: Make sure you do this in the container view controller, if your UITableView is placed on a controller which is then embedded into another controller, do this in the embedding top controller, not directly the one where you put the UITableView (where AutoLayout will take care of things). – James Stone Aug 14 '14 at 10:29
  • This is better than `uncheck Adjust scroll view insets`. Because sometimes we don't use storyboard to build our UI. – JW.ZG Sep 19 '16 at 20:02
  • This works for me. I attached view to navigation bar and tableview, it does not happened in iOS 11, but it occurs in iOS 10. Thank. – dobiho Feb 06 '18 at 03:01
  • `'automaticallyAdjustsScrollViewInsets' was deprecated in iOS 11.0: Use UIScrollView's contentInsetAdjustmentBehavior instead` – Nike Kov Oct 05 '18 at 10:43
  • 3
    This was deprecated in iOS 11.0. Xcode will warn you about this. Use this instead, on the scroll view that you don't want insets automatically adjusted on: `self.tableView.contentInsetAdjustmentBehavior = .never` – David Topolansky Aug 20 '19 at 01:09
86

Solution for iOS 15:

if #available(iOS 15.0, *) {
  tableView.sectionHeaderTopPadding = 0
}

To fix in a whole project:

if #available(iOS 15.0, *) {
    UITableView.appearance().sectionHeaderTopPadding = 0
}

More details: Extra padding above table view headers in iOS 15

Note: This only applies to UITableView.Style.plain.

Levan Karanadze
  • 739
  • 1
  • 11
  • 21
81

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 CGFLOAT_MIN;
}

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

This maybe is not an elegant solution but works for me

Swift version:

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

override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}
Suraj Mirajkar
  • 1,369
  • 10
  • 23
LightMan
  • 3,517
  • 31
  • 31
  • 1
    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
  • 5
    You can use CGFLOAT_MIN instead of 0.001 it gives you the smallest absolute value of CGFloat. – KaroCodes Sep 11 '15 at 09:07
  • 2
    This is the correct answer since the real feature is that padding is there only in the grouped style table view and is ignored if you specify the header/footer – Jakub Truhlář May 06 '16 at 10:55
  • This should be marked as the correct answer. A delegate method to override and it answers the question. At least try this first if you read this far down all the hacks. Try tweeting : -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { //return CGFLOAT_MIN; return 30.0f; } – Matthew Ferguson Aug 02 '18 at 02:25
  • Nice! As a bonus, if you want a little header on top and more in between the grouped sections, you can use the following: `override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return section == 0 ? 14 : 24 }` – Freek Sanders Apr 16 '19 at 09:04
  • This is the best solution because using plain style would change the behavior of the header/footer. Thanks! – Bruno Muniz Sep 18 '19 at 01:27
60

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.

esilver
  • 27,713
  • 23
  • 122
  • 168
  • 21
    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 07 '13 at 05:25
  • 1
    YES!! I've tried 3 so called solutions, and this was the one! Brilliant, thanks :D – Henrik Erlandsson Oct 08 '13 at 08:43
  • perfect. Anyone reported a bug because I think this is not the intended behaviour. – Pushparaj Dec 02 '14 at 05: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 '15 at 12:32
  • great debugging, thanks. IMO the solution of setting the tableHeaderView is the most portable and self contained. – Sam Dec 08 '16 at 15:03
  • This is the correct answer! Unfortunately on iOS 11.3 the bug still exists. – rpstw Apr 02 '18 at 06:06
  • 2
    Setting estimatedHeight for header helped me – Viktor Sep 07 '18 at 16:09
50

Uncheck "Adjust Scroll View insets"

enter image description here

Dani Pralea
  • 4,545
  • 2
  • 31
  • 49
Tú Đt
  • 549
  • 4
  • 4
46

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

enter image description here

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.

enter image description here

(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.)

Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
  • 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 '15 at 09:13
  • 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 '15 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 '15 at 08:25
  • 4
    1 million thank you's! This is the only solution which worked for me. – user139816 Aug 12 '15 at 11:58
  • Glad it worked for you ! Don't forget to click on the "up arrow" to vote up this answer, if it's helped you. – Mike Gledhill Aug 12 '15 at 12:40
  • There is just one thing to say to this: LOL. And it's not the funny kind of LOL, its the "give me back 2 hours of my life LOL" – Dave Sep 16 '15 at 08:06
  • Annoyingly this actually made a difference - Filing a bug report with Apple – AppHandwerker Oct 23 '15 at 11:22
  • 1
    (I'm amazed its 18 months later, and readers are still voting up this answer. Has Apple seriously not fixed this issue yet ?!) – Mike Gledhill Oct 14 '16 at 09:44
  • 1
    saved my life! thanks. do you know how long it took to find this simple little "fix"? grrh. – Mc.Stever Nov 25 '16 at 13:34
  • Paul: Pathetic, isn't it ? The richest technology company in the world, and Xcode is still as appallingly bad and user-unfriendly as ever. Our only hope as we enter 2017 is that Microsoft will finally make Xamarin stable at last (gasp!) so we don't have to cope with Xcode anymore...! – Mike Gledhill Dec 31 '16 at 07:58
  • 1
    Still same issue with Xcode 8.2.1. So be careful with the components hierarchy. – YMonnier Mar 25 '17 at 15:43
  • 1
    I confirm that this problem is unbelievably still happening with Xcode 8.3.2 (Swift 3). The fix works! Thanks a lot! – Claus Jun 02 '17 at 10:09
  • It's Sep 2017 and this problem still happening with Xcode 9 (Swift 3) (build target IOS 9 has problem, target IOS 11 is OK). The fix works like a charm! – Yaiba Sep 30 '17 at 10:39
  • I don't understand your solution. drag and drop the tableView where?! – mfaani Nov 14 '17 at 17:25
  • @Honey: if you have a TableView on your screen, but it's showing this behavior, then, yes, drag'n'drop it from the *first* position to a lower position in the tree. It's a bug in iOS, and doesn't seem to be going away... – Mike Gledhill Nov 15 '17 at 09:23
  • FYI I'm only seeing this issue on iOS9. I don't see it on iOS10 or iOS11... **1.** I'm doing this all programatically. Does this still apply? **2.** my tableView is the only subView in the viewController (in which this viewController itself is added as a childViewController to another viewController). Does it still apply? – mfaani Nov 15 '17 at 15:27
  • I finally got it fixed. For anyone interested see [this](https://stackoverflow.com/a/47423394/5175709) answer for how – mfaani Nov 22 '17 at 16:06
43

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

self.tableView.contentInset = UIEdgeInsetsMake(-35, 0, 0, 0);
Aqib Mumtaz
  • 4,936
  • 1
  • 36
  • 33
40

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.

girish_vr
  • 3,041
  • 1
  • 24
  • 27
  • 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. – Genki Apr 21 '14 at 21:26
  • This is the answer to a different problem. – entonio Nov 09 '14 at 04:09
  • Thank you it worked for me, in my particular case I had a tableviewcontroller embedded in the viewcontroller, and by setting automaticallyAdjustsScrollViewInsets = false in the viewcontroller the top gap disappeared – Alexey Mar 02 '16 at 09:37
39

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. a 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;
Aurelien Porte
  • 2,692
  • 27
  • 32
  • Finally, I found the answer that works. Thanks. Besides, I learnt that `tableView.tableHeaderView` is actually an accessory view above row content. I was confused with section headers all the way until your answer came out. – Joe Huang May 31 '16 at 01:40
  • 1
    `CGFLOAT_MIN` has been replaced with `CGFloat.leastNormalMagnitude` in Swift 3 – Clay Ellis Apr 03 '17 at 18:12
29

Storyboard:

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

enter image description here

Code:

self.automaticallyAdjustsScrollViewInsets = false
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
28

This code worked for me, The best answer for me that was written in objective-C at up-side so I converted it into Swift.

For Swift 4.0+

self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: .leastNonzeroMagnitude))

Just write this into viewDidLoad() and it will work like a charm.

For iOS 15+, above one won't work, so use this:-

 if #available(iOS 15.0, *) {
      tableView.sectionHeaderTopPadding = 0
 }

For iOS 15+, if you want to apply change for your whole project, so use this:-

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    if #available(iOS 15.0, *) {
        UITableView.appearance().sectionHeaderTopPadding = 0.0
    }
}
Vipul Kumar
  • 893
  • 9
  • 19
25

This is the solution for iOS 10 using Swift 3:

You can get rid of top and bottom paddings by implementing the following methods from the UITableViewDelegate.

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

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
   return CGFloat.leastNormalMagnitude
}
shim
  • 9,289
  • 12
  • 69
  • 108
Andi
  • 8,154
  • 3
  • 30
  • 34
  • Second page on SO helped me.... I dont know why, maybe because of the AutomaticDimension, maybe because of the Constraints with the VFL, anyhow, thank you! ozi bua ist brav! :D – Pentarex Jan 21 '17 at 01:41
  • These are the **section** headers and footers. The question relates to the whole table header. Also, there is nothing specific to Swift3 or iOS 10 in either delegate method (they've been around since forever). – Nicolas Miari Apr 20 '17 at 06:23
16

So I was trying every method here, and this time none of them helped. My case was a grouped table view on iOS 9. I don't really know why and how I found out this one, but for me, setting the tableViewHeader with a UIView with at least 0.01 height worked out. CGRectZero didn't help, nothing really helped:

tableView.tableHeaderView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.01))
sunshinejr
  • 4,834
  • 2
  • 22
  • 32
15

Simply add the following to your viewDidLoad in your VC:

self.automaticallyAdjustsScrollViewInsets = NO;
judepereira
  • 1,239
  • 2
  • 17
  • 24
14

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;
}
Lukas
  • 2,515
  • 4
  • 28
  • 37
  • 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 07: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 08: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
  • Grouped tableviews has some extra space by default, maybe that's new apple design solutions? I'm still looking for some real explanations. – Lukas Oct 31 '13 at 14:46
  • Mike M is right. We only need to set `self.automaticallyAdjustsScrollViewInsets` to NO. And in my case, I place it right at the containing controller. The problematic UIScrollView instance is a UITableView right inside its child controller. – MkVal Dec 20 '13 at 05:33
13

This is how it can be fixed easily in iOS 11 and Xcode 9.1 through Storyboard:

Select Table View > Size Inspector > Content Insets: Never

Saeed Ir
  • 1,974
  • 2
  • 20
  • 22
11

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.

Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
11

To be specific, to remove tableviewHeader space from top i made these changes:

YouStoryboard.storyboard > YouViewController > Select TableView > Size inspector > Content insets - Set it to never.

enter image description here

user832
  • 796
  • 5
  • 18
  • What's the additional information other than the screenshot in comparison to [this answer](https://stackoverflow.com/a/47070700/1816580)? – Artjom B. Apr 14 '18 at 12:34
  • it is the same I guess, I didn't find that answer when I was looking for a solution. Should I delete my answer then..? – user832 Apr 17 '18 at 06:53
  • Not if you can expand a bit on your answer by describing why Content insets = Never actually solves this issue (how does this option work?). – Artjom B. Apr 17 '18 at 19:23
  • When content insets is set to never, the tableView will not scroll up on textField editing. – mojtaba al moussawi Apr 30 '19 at 09:26
10

Thanks to the answer by @Aurelien Porte. Here is my solution

Cause of this issue:-

  1. a 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.

In ViewDidLoad:-

self.edgesForExtendedLayout = UIRectEdge.None

self.automaticallyAdjustsScrollViewInsets = false

No Need For Something Like This :-

self.myTableview.contentInset = UIEdgeInsetsMake(-56, 0, 0, 0)

In heightForHeaderInSection delegate:-

if section == 0
    {
        return 1
    }
    else
    {
        return 40; // your other headers height value
    }

In viewForHeaderInSection delegate :-

if section == 0 
{  
   // Note CGFloat.min for swift
   // For Objective-c CGFLOAT_MIN 
   let headerView = UIView.init(frame: CGRectMake(0.0, 0.0, self.myShaadiTableview.bounds.size.width, CGFloat.min)) 
   return headerView
}
else
{ 
   // Construct your other headers here 
}
Ashish P
  • 1,463
  • 1
  • 20
  • 29
10

The only thing that worked for me was:

Swift:

tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0

Objective-C:

self.tableView.sectionHeaderHeight = 0;
self.tableView.sectionFooterHeight = 0;

Also, I still had an extra space for the first section. That was because I was using the tableHeaderView property incorrectly. Fixed that as well by adding:

self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 0.01))
Dani Pralea
  • 4,545
  • 2
  • 31
  • 49
  • Works for me for Swift 4.2. Thanks – Sylar Feb 14 '19 at 09:38
  • Tried everything in this page, for iOS13 grouped tableview with header view. self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 0.01)) . fixed the issue. – Ning Sep 12 '19 at 22:43
10

2022 answer:

You just do this

tableView.contentInsetAdjustmentBehavior = .never

which is undocumented

Bizarre subtle gotchya ->

Tableviews have a very strange behavior these days:

  1. On devices with a notch (XR, etc) it will without telling you add more inset BUT ONLY IF the table starts at the physical top of the screen.

  2. If you start NOT at the top of the screen, it won't do that, but

  3. Both of those cases are >> unrelated << to safeAreaInsets ....... which is very confusing

All of that is totally undocumented ... you can waste hours figuring this out.

If you do need your measurements to start actually from the top of the screen/table,

in fact simply go:

tableView.contentInsetAdjustmentBehavior = .never

A good example is obviously when you add some sort of banner or similar thing over the top of a table, which is common these days, and you just set the top inset of the table to whatever height your banner/etc becomes when it's running.

To do that, you must use the

tableView.contentInsetAdjustmentBehavior = .never

call :/

Bonus gotchya

Don't forget that almost always these days, you're loading some information (user pictures, description, whatever) dynamically, so you can't set such values to the final needed value until the info arrives. Another gotchya. :/

So you'd have code like:

func setTableOffsetOnceFlagAreaSizeIsKnown() {
    tableView.contentInset.top = yourSpecialFlagViewUpTop.bounds.height
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    setTableOffsetOnceFlagAreaSizeIsKnown()
}
Fattie
  • 27,874
  • 70
  • 431
  • 719
9

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];
    }
}
Kevin
  • 3,111
  • 1
  • 19
  • 26
  • 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 ;) – Dan Rosenstark Sep 18 '13 at 20:28
  • Whoops, yeah. Meant to write that warning but forgot. – Kevin Sep 19 '13 at 01: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 03:46
  • 1
    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 06:54
9

My answer is going to be more general answer, but can be applied on this as well.

If the root view (of the ViewController) or the first child (subview) of the root view is subclass of the UIScrollView (or UIScrollView itself), and if

self.navigationController.navigationBar.translucent = YES;

framework will automatically set pre-calculated contentInset.


To avoid this you can do

self.automaticallyAdjustsScrollViewInsets = NO;

but in my case I wasn't able to do this, because I was implementing SDK which has UIView component which can be used by other developers. That UIView component contains UIWebView (which has UIScrollView as the first subview). If that component is added as the first child in the UIViewController's view hierarchy, automatic insets will be applied by system.

I've fixed this by adding dummy view with frame (0,0,0,0) before adding UIWebView.

In this case system didn't find subclass of the UIScrollView as the first subview and didn't apply insets

zvjerka24
  • 1,772
  • 1
  • 21
  • 27
9

Swift 4 code: For tableview with no section headers you can add this code:

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

and you will get the header spacing to 0.

If you want a header of your specific height pass that value:

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

and the view from viewForHeaderinSection delegate.

Sunil
  • 3,404
  • 10
  • 23
  • 31
  • This doesn't answer the question. The question was about where the extra spacing is coming from, not how to get rid of it. – Stephen Newell Feb 27 '18 at 02:25
  • weird thing is that if u return 0 in heightForHeaderInsection u still get this extra space. It works perfect with CGFloat.leastNormalMagnitude ( least positive number) – ShadeToD Mar 17 '19 at 09:20
7

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.

Oded
  • 954
  • 12
  • 16
  • 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. – Mic Fok Nov 12 '14 at 08: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 '15 at 18:49
7

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.

Jiangfan Du
  • 137
  • 1
  • 5
  • 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 02:16
7

use this one i think this help...

 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
 {
    return 0.005f;// set this according to that you want...
 }
Shahzaib Maqbool
  • 1,479
  • 16
  • 25
  • 1
    Brilliant! Works like a charm in iOS 9.2. This answer is perfect since in some cases I need to suppress the first header while in others show it. I saw another answer using CGFloat.min, that works too. So my viewController can now supply either a real number like 44.0 or essentially 0. – David H Jan 27 '16 at 16:28
6

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

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

LorikMalorik
  • 2,001
  • 1
  • 14
  • 14
6
override func viewWillAppear(animated: Bool) {
        self.edgesForExtendedLayout = UIRectEdge.None

 //  OR

self.sampleTableView.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0);

   //OR

 self.automaticallyAdjustsScrollViewInsets = false
        }
Alvin George
  • 14,148
  • 92
  • 64
6
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{

    return CGFLOAT_MIN;
}

That's all folks!

HannahCarney
  • 3,441
  • 2
  • 26
  • 32
6

We have multiple answers for this.

1) You can add UIImageview at view didload

UIImageView * imbBackground = [UIImageView new];
[self.view addSubview:imbBackground];

2) You can set header and footer height 0.1

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

3) You can add header and footer view with height 0.1

tblCampaigns.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tblCampaigns.bounds.size.width, 0.01f)];
tblCampaigns.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tblCampaigns.bounds.size.width, 0.01f)];
Hari c
  • 1,139
  • 11
  • 11
6

This one line of code will make you happy.

override func viewDidLoad() {
        super.viewDidLoad()
        if #available(iOS 15.0, *) {
            tableView.sectionHeaderTopPadding = CGFloat(0)
        }
    }
Kumar Lav
  • 234
  • 1
  • 3
  • 9
5

Swift3

If you are using grouped table then do following things . This will remove top space.

    var frame = CGRect.zero
    frame.size.height = .leastNormalMagnitude
    self.tableView.tableHeaderView = UIView(frame: frame)
    self.tableView.tableFooterView = UIView(frame: frame)

If you Still getting this issue then it will remove by default content offset from top.

[Set content insets never]
https://i.stack.imgur.com/fjxOV.png

beryllium
  • 29,669
  • 15
  • 106
  • 125
4

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...

arielyz
  • 608
  • 1
  • 5
  • 6
  • 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 03 '14 at 10:44
4

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.

latenitecoder
  • 746
  • 7
  • 13
  • Yep, I wonder how so many people accept an answer without testing all consequences of those settings... [screenshot](http://i.imgur.com/2ZNci4H.png) – Nicolinux May 12 '16 at 09:43
4

When you need to hide your tableHeaderView, you should use this Swift 3 code:

tableView.tableHeaderView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 0.0, height: CGFloat.leastNormalMagnitude)))
Jan Černý
  • 1,268
  • 2
  • 17
  • 31
4
tableView.contentInsetAdjustmentBehavior = .never

was the solution for me (iOS12 / xcode 10) on a plain tableview with headers

david
  • 119
  • 2
4

self.automaticallyAdjustsScrollViewInsets = NO;

This was deprecated in iOS 11, so you should use new property contentInsetAdjustmentBehavior in your code, it should fix the problem.

if #available(iOS 11.0, *) {
    collectionView.contentInsetAdjustmentBehavior = .never
}

There is a new property on UIScrollView called contentInsetAdjustmentBehavior added in iOS 11 to determine adjust content offset

Aks
  • 1,567
  • 13
  • 23
4

Swift 4 answer...

If the table view is selected in interface builder and in the attributes inspector the style "Grouped" is selected, enter the following code in your view controller to fix the extra header space issue.

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat.leastNonzeroMagnitude
}
F. Morales
  • 437
  • 6
  • 5
4

When you use UITableView.Style.grouped or UITableView.Style.InsetGrouped the tableview will automatically add a top inset padding to the "section header" if no "tableview header" is present, the fix is simple:

 self.tableview.tableFooterView = UIView(frame: CGRect.init(origin: .zero, size: CGSize.init(width: tableview.frame.size.width, height: 1)))
 self.tableview.tableHeaderView = UIView(frame: CGRect.init(origin: .zero, size: CGSize.init(width: tableview.frame.size.width, height: 1)))

If you are using UITableView.Style.Plain

self.tableview.contentInsetAdjustmentBehavior = .never

Will generally be sufficient

  • This feels a bit too much like a hack/quick-fix. Also, the 1 pixel is still visible, thus not a good solution. EDIT: I see someone answered the same (https://stackoverflow.com/a/56161981/2399348) but with 0.01. That works better – Jeroen Apr 03 '20 at 06:01
3

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 <number_of_data_sections>+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.

Yevhen Dubinin
  • 4,657
  • 3
  • 34
  • 57
3

if you choose the style of UITableViewStyleGrouped,you need to implement the Header and Footer height delegate method,and the return value need greater than 0; like this:

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

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return CGFLOAT_MIN;
}
MichaelMao
  • 528
  • 6
  • 15
3

According to the Apple documentation:

When assigning a view to this property, set the height of that view to a nonzero value. The table view respects only the height of your view's frame rectangle; it adjusts the width of your header view automatically to match the table view's width.

Swift 5

If you have a grouped UITableView where you want a tableHeaderView:

Before assigning a view to tableView.tableHeaderView, set the height of that view to a nonzero value, e.g:

// Set the initial height of your custom view to the smallest value  
myTableHeaderView.frame.size.height = .leastNonzeroMagnitude

// Assign your custom view to the header view
tableView.tableHeaderView = myTableHeaderView

// Set width constraint, height should grow based on your view. 
tableView.tableHeaderView!.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true

No need for magic with contentInsets or handling delegate methods.

Hapeki
  • 2,153
  • 1
  • 20
  • 36
2

With storyboard:

Make sure that your UITableView top constraint doesn't say "Under top layout guide". Instead it should say "Top space to: Superview" (Superview.Top).

Plus of course in the UIViewController that contains the UITableView uncheck "Adjust Scroll View Insets".

konsti
  • 629
  • 5
  • 8
2

I have a VC with a Container in it (which btw is part of a Nav controller), and embedded in that is a TableVC.

Selecting my TableVC, looking at the attributes panel:

  • uncheck automatically adjust scroll insets
  • uncheck extend edges under top bar

Then I set the autoconstraint for the Container relative to the parent view as:

Container View.top = ParentView.Top Margin

This accomplishes the following for me:

  • keeps the table pulled up to the top but just beneath my nav bar
  • after refreshing, the table returns to this position and not up+under the nav bar as it was doing
  • after scrolling the table bottoms out at the actual bottom, not short of it

Lots of trial and error for me with this setup, but I eventually found these little details posted by lekksi @ Remove empty space before cells in UITableView

Community
  • 1
  • 1
the_dude_abides
  • 563
  • 4
  • 10
2

For me, I tried all the solutions but I was thinking to set height for UITableView section and it's working for me.(Using swift)

 func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 0.001
    }
Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52
2

I had this exact problem, but with a tableView inside a tableView cell. Nothing worked from the numerous answers from above. A very odd and simple thing worked:

- Put the estimated heights before assigning the delegate for the tableView!!

    override func awakeFromNib() {
        super.awakeFromNib()

        tableView.estimatedRowHeight = 58
        tableView.estimatedSectionHeaderHeight = 45
        tableView.estimatedSectionFooterHeight = 10
        tableView.dataSource = self
        tableView.delegate = self
    }

Putting the estimates after the delegate assignment, caused my inner tableView to have an odd white space above the header. I hope it helps someone here.

Starsky
  • 1,829
  • 18
  • 25
2
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat.leastNonzeroMagnitude
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNonzeroMagnitude
}
Serg Smyk
  • 613
  • 5
  • 11
2
    if #available(iOS 15.0, *) {
        tableView.sectionHeaderTopPadding = 0
    }

Put this code, it will work

Vinayak
  • 329
  • 1
  • 3
  • 10
1

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:

enter image description here

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 https://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.

Community
  • 1
  • 1
Matthew Quiros
  • 13,385
  • 12
  • 87
  • 132
1

Make sure that you have given constraints to the table. I hadn't and faced the similar issue of having an unexplained padding at the bottom of table.

Yash Tamakuwala
  • 1,789
  • 1
  • 24
  • 33
1

Yet another way of doing it... but I like it because it avoids hardcoding any height value.

In a UITableViewStyleGrouped table (static or dynamic), just assign the desired height in tableView(_:heightForHeaderInSection). I'm calculating the new height based on the bottom padding for the section header label.

override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

    var height = UITableViewAutomaticDimension

    if section == 0, let header = tableView.headerViewForSection(section) {
        if let label = header.textLabel {
            // get padding below label
            let bottomPadding = header.frame.height - label.frame.origin.y - label.frame.height
            // use it as top padding
            height = label.frame.height + (2 * bottomPadding)
        }
    }

    return height
}

Tested on iOS 9, Xcode 7.3.

Hope it helps.

maganap
  • 2,414
  • 21
  • 24
1

In my case there was unwanted cell called "HeaderView" on prototype visualization in Storyboard, when I deleted it everything was good.

Robert Juz
  • 126
  • 7
1

I went through all answers. None worked for me. All I had to do was:

self.myTableView.rowHeight = UITableViewAutomaticDimension
self.myTableView.estimatedRowHeight = 44.0

Additionally the issue wasn't happening at the top of tableView. It was happening at the top of each section of the tableView.

FWIW this issue was only happening for iOS9. Our app worked fine for iOS10 and iOS 11.

I highly recommend you to see this awesome question and its top answers:

Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • Similar to this answer, the extra space I was seeing only at the top of the tableview (not at the top of each section) seemed to be caused by not returning a `> 0` value in the delegate method `func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath)`. This was even though I'd already indicated I wasn't going to use an estimated height for that index path in `func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)` by returning a constant. It appears as though you can't selectively mix height constants and `UITableViewAutomaticDimension`. – Evan R Jun 04 '18 at 17:34
  • Note: this occurred in iOS 10 & 11 for me. – Evan R Jun 04 '18 at 17:35
1
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 0.0
}

This worked for me. Also one can give height for header based on the section.

Sujan
  • 147
  • 1
  • 3
1

if self.automaticallyAdjustsScrollViewInsets = NO; doesn't work for you, make sure the height of either tableview header or section header is CGFLOAT_MIN not 0.

For example if you want to make tableview header 0 high, you can do:

    CGRect frame = self.tableViewHeader.frame;
    frame.size.height = CGFLOAT_MIN; //not 0
    self.tableView.tableHeaderView.frame = frame;
    self.tableView.tableHeaderView = self.tableViewHeader;

Hope it helps.

coolbeet
  • 1,645
  • 1
  • 18
  • 20
1

if I add a tableHeaderView with a really small height, it fixes the problem

    let v = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.000000001))
    tableViewDocuments.tableHeaderView = v
MobileMon
  • 8,341
  • 5
  • 56
  • 75
1

Please check if the tableview is grouped/plain. In my case I have changed the style to plain and it worked. Now the extra spacing above the header has disappeared.

vinny
  • 360
  • 3
  • 10
1

just unchecking Adjust Scroll View Insets didn't work for me.
Later, I tried to set tableview's header to nil, which fortunately worked.

self.tableView.tableHeaderView = nil
Kiran Jasvanee
  • 6,362
  • 1
  • 36
  • 52
1

for the first section, we need to set tableHeaderView like this:

tableView.tableHeaderView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 0.0, height: .leastNonzeroMagnitude))

and also for the other sections, we should set heightForFooterInSection like this:

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return .leastNonzeroMagnitude
}
Alessandro Francucci
  • 1,528
  • 17
  • 25
Hasan
  • 11
  • 2
1

2021 Xcode 12.3 update

To solve this problem one would need to disable the standard section footer. The following snippet does the job:

override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
    return nil
}

override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return 0
}

Usage of

tableView.contentInsetAdjustmentBehavior = .never

is completely unrelated here

Nik
  • 9,063
  • 7
  • 66
  • 81
1

For iOS 15, try below solution in viewDidLoad:

if #available(iOS 15.0, *) {
    tableView.sectionHeaderTopPadding = .leastNormalMagnitude
}
Mahesh K
  • 373
  • 2
  • 8
1

if you have this issue in iOS 15 or higher just do this:

if #available(iOS 15.0, *) {
    self.tableView.sectionHeaderTopPadding = 0
}
shndrs
  • 11
  • 2
0

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.

Community
  • 1
  • 1
MQoder
  • 712
  • 8
  • 21
0

I am not sure if this good answer but it works with me

I select Table View , navigate to ruler , change Y value to be zero

enter image description here

Mina Fawzy
  • 20,852
  • 17
  • 133
  • 156
0

None of the previous answers worked for me. What did end up working for my situation (which was seeing that padding after dynamically adding a header to my Table View) was selecting the Navigation Bar from the Document Outline and rechecking the Translucent box (contrary to some answers that were saying to force it to be translucent). I had previously unchecked it because it had made my red look a little orange, but I could not try the solution of reordering the elements in the scene since the Table View was the only element in this scene. This solution works as long as you are okay with the Navigation Bar's color having a translucent layer over it. Hope this helps :)

jeff t
  • 1
0

Finally figured how to fix this after trying everything!

I noticed that for some reason the contentOffset of my tableview had a 'y' of -20 so when configuring my tableview: swift 3/4

tableView.contentOffset = .zero

Objective-C

self.tableView.contentOffset = CGPointMake(0, 44);
shim
  • 9,289
  • 12
  • 69
  • 108
Jason Silver
  • 706
  • 7
  • 10
0

Using swift 4.1. Try this:

func tableView(_ tableView: UITableView, viewForHeaderInSection 
section: Int) -> UIView? {
    return nil 
}
ali ziwa
  • 11
  • 4
0

None of the answers or work-arounds helped me. Most were dealing with the tableView itself. What was causing the issue for me was the view I was adding the tableView or collectionView onto. This is what fixed it for me:

SWIFT 5

edgesForExtendedLayout = []

I put that in my viewDidLoad and the annoying gap went away. Hope this helps.

c0d3p03t
  • 1,675
  • 2
  • 16
  • 14
0
set
  override func viewDidLoad() {
  self.tableView.delegate = self
  self.tableView.dataSource = self
}
showdev
  • 28,454
  • 37
  • 55
  • 73
0

I had faced the extra top space issue, I had to club a bunch of answers to reach the solution. (5 hours of checking all answers given)

first if your concerned

Table view - mode is "Group" please change it to "Plain"

no need to do any changes to header or footer section, or add additional delegate methods related to them

Then in the ViewController that has your TableView in InterfaceBuilder - Uncheck Adjust Scroll View Insets - Uncheck Extend edges: Under Top Bars

*Also, make sure you are deleting derived data and re-installing your app in simulator or phone to reflect the changes done effectively.

UI changes sometimes don't reflect because of IDE also...enter image description here

pandu
  • 47
  • 10
0

enter image description here

Setting content Insets to Never solved the problem for me.

Idrees Ashraf
  • 1,363
  • 21
  • 38
-1

Throwing my ten cents in - I had the same problem after I removed a header cell from a tableview. To resolve I changed the TableView Style in the Attributes Inspector from "Grouped" to "Plain" and the extra space was removed.

AndyOS
  • 3,607
  • 3
  • 23
  • 31
-1

if you use snapkit, then code is here.


self.tableView.snp.makeConstraints { make in
    make.top.equalToSuperview().inset(-35)
    make.leading.trailing.equalToSuperview().inset(0)
    make.bottom.equalTo(self.view.safeAreaLayoutGuide)
}

on XCode 13.2.1 and swift 5.0