why extra space is at top of UITableView - simple - ios

I'm picking up some iOS programming and am trying to put a UITableView into a storyboard. Unfortunately, I am trying to put the content at the top of the view but it is putting in some space. I have tried to adjust the values in the inspector for View -> Mode but this doesn't seem to have any effect.
I have made the background green and put a border color to show the issue. I'm not a sophisticasted iOS dev, so I'd assume that this is the simplest solution and not something complex. How do I make the contents of the table view sit flush with the top? I've seen this Why is there extra padding at the top of my UITableView with style UITableViewStyleGrouped in iOS7 but not sure if it's related.
thx for any help
Edit #1
Updated with changes and screen shot of properties for this table view

Yes, that other question is very much related. UITableViewStyleGrouped divides each section into a "group" by inserting that extra padding…similar to what it did pre-iOS7, but clear instead of colored by default, and just at the top instead of all the way around. If you don't want the padding by default, use UITableViewStylePlain.
Otherwise, if you need to keep the style the same, do what this other posted from that link recommended and change the content inset:
self.tableView.contentInset = UIEdgeInsetsMake(-36, 0, 0, 0);
Or do what this poster suggested and set the tableHeaderView's height to .-1, i.e. nearly 0:
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width, 0.01f)];

Go to the attributes inspector of the View Controller by selecting the xib or the controller in Storyboard. Uncheck the Adjust Scroll View Insets in Layout. It will solve the problem

Everybody keeps talking about this self.automaticallyAdjustsScrollViewInsets option.
However this did not work for me at all. What did work for me, was setting the "Content Insets" property to Never.
Such an annoying problem.

In Swift, you just need to set the below property to false.
self.automaticallyAdjustsScrollViewInsets = false

It is very easy and worked for me perfectly.
Select a controller in Story Board in which you placed UITableView.
YouStoryboard.storyboard > YouViewController > Attributes inspector > Uncheck - Adjust scroll view insets.
Make sure you select UIViewController not UITableView.

Swift :
override func viewWillAppear(animated: Bool) {
self.edgesForExtendedLayout = UIRectEdge.None
OR
self.moduleListTableView.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0);
OR
self.automaticallyAdjustsScrollViewInsets = false
}

try this....
self.tableView.contentInset = UIEdgeInsetsMake( 20, 20 , 0, 0)

in swift 3.0, i hope will help you
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}

This is how it can be fixed easily through Storyboard:
Select Table View > Size Inspector > Content Insets: Never

Cause of this issue:-
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.
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
}

Maybe you have more than one parent navigation controller? If that's the case, uncheck other parent navigation controllers' "Show Navigation Bar".

This worked for me in swift:
tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))

For iOS 15.0+,
use this for removing extra padding at the top
if #available(iOS 15.0, *){
self.tableView.sectionHeaderTopPadding = 0.0
}

Related

iOS 11 Extra top space in UITableView

When I updated my app on iOS 11 SDK , TableView started behaving Weird , It is adding extra top space , but actually that extra space is Cell itself but it is not rendered , please look through attached image before ios 11 update and after.
Thank you!
Set new property contentInsetAdjustmentBehavior in your code, it would 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
This property specifies how the safe area insets are used to modify
the content area of the scroll view. The default value of this
property is automatic.
I don't know why but when I add table view programmatically that space occurs. All you need is returning empty view in viewForHeaderInSection
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return UIView()
}
If you want zero space, add it too,
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.01
}
Also, I realized that bug appears only in Swift4.
only happened on iOS 11 for me, my fix:
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];
OR
self.tableView.tableHeaderView = UIView(frame: CGRect(x:0,y:0,width:0,height:CGFLOAT_MIN))
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...
It appears that adding gradient layer to TableView in iOS 11 creates this problem

Hide First Section Header of a TableView Grouped in a UITableViewController - Swift 3 - Xcode8

This is my very first post here.
I need to mention I'm not a coder, I'm a UX designer and I'm trying to get fluent with Xcode Storyboard+ to build better prototypes for my fellow Engeneers.
The issue
I'm trying to give a "native" look to my profile view.
Right now my profile view is a UITableViewController.
I realized that the "native" look comes with the settings "grouped" applied to the TableView.
Here is how it looks compare to my previous version, not using "grouped"
As you can see, the grouped version pushed my TableView down because of the header. I haven't entered any text in the Header settings. Yet the space is taken by a fixed margin.
I want to get rid of that space.
I've found this code on Stack, that sounded like should be solving my issue.
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
let headerHeight: CGFloat
switch section {
case 0:
// hide the header
headerHeight = CGFloat.leastNonzeroMagnitude
default:
headerHeight = 21
}
return headerHeight
}
I've added this in my ProfileTableViewController.swift inside the super.viewDidLoad().
But the space remains and I am now out of options.
Maybe the problem comes from the header/footer settings and not even the section title... not even sure anymore.
The latest two options offered by #Pragnesh are working for me.
I'm not sure shifting the tableview up is the best practice ever, but it does the trick for now.
I'm sure there is still a way to just hide the section header.
I've been using this
self.tableView.contentInset = UIEdgeInsetsMake(-35, 0, 0, 0)
Try this:
In storyboard/xib:
1. Click TableView.
2. Click on Size Inspector on Right side.
3. You will see SectionHeight: Header and Footer.
4. Make both these values 1.
5. It will remove the extra spaces.
Set 1 as the first section header's height. Then I use the contentInset to hide that height underneath the navigation bar.Given below -
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 0)
return 1.0f;
return 32.0f;
}
- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
if (section == 0) {
return nil;
} else {
// return some string here ...
}
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.tableView.contentInset = UIEdgeInsetsMake(-1.0f, 0.0f, 0.0f, 0.0);
}
You can try this code in viewDidLoad():
1). In viewDidLoad():
self.automaticallyAdjustsScrollViewInsets = false
2). Either you can write this in viewDidLoad():
self.tableView.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0)
3). Or you can write this:
self.tableView.contentInset = UIEdgeInsetsMake(-20, 0, -20, 0);
The other answers work, but I'd rather not mess around with hardcoded insets.
An improvement to #niku solution could be using CGFloat.leastNonzeroMagnitude
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return CGFloat.leastNonzeroMagnitude
}
// return the height for the other sections
}

Add text under table sections in UITableView

I was trying to mimic a view like the iOS 7 "Shortcut".
I used a UITableViewController with static cells, 1 section and 2 rows. For the text "Create a shortcut that ...", I tried UILabel as well as the section footer. The problem with footer was that I could not figure out a way to wrap the long text to multiple lines. So I am curious about what's the "standard" or preferred way to implement the text under sections? Thanks!
If you select the Table View Section in the storyboard and enter your text in the 'Footer' it will automatically wrap.
If you want more control over the font you can set a custom footer view using -[UITableViewDelegate tableView:viewForFooterInSection:]
The following code replicates what you've shown above. Instead of creating a label and returning it, I created a simple UIView that was some arbitrary hard-coded height (you may want to change that to suit your needs), and then created a label and added the label to the view, returning the view, so that you could center the label in the view as I did when I created the frame. By setting the number of lines to 0 you are effectively telling the label there will be multiple lines, and I set an autoresizing mask on the label so that if the view rotates the text will still remain centered in the view with 10 points padding on either side. You'll also want to make sure you are returning the appropriate heightForFooterInSection in case you decide to add something below it later it won't be overlapping your footer.
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 80)];
UILabel *explanationLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.view.frame.size.width - 20, 80)];
explanationLabel.textColor = [UIColor darkGrayColor];
explanationLabel.numberOfLines = 0;
explanationLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
explanationLabel.text = #"Create a shortcut that will automatically expand into the word or phrase as you type.";
[footerView addSubview:explanationLabel];
return footerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 80;
}
Gave me this:
SWIFT 4 Version
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 80))
let explanationLabel = UILabel(frame: CGRect(x: 10, y: 0, width: view.frame.size.width - 20, height: 80))
explanationLabel.textColor = UIColor.darkGray
explanationLabel.numberOfLines = 0
explanationLabel.text = tableDataSectionFooters[section]
footerView.addSubview(explanationLabel as? UIView ?? UIView())
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 80
}
Use UILabel in the footer and set it to wrap lines (number of lines = 0)
all other answers are right in using the UILabel, but to achieve the 100% identical effect you must use the attributedText property of the label. Than you can also add the indention showed in the original shortcut screenshot.

UITableView: the proper way to display a separator for the last cell

The question is what's the right-most way to display a separator in the last cell in a table/section.
Basically this is what I am after.
This is from the native music app, which makes me think that it should be possible to achieve just by means of UITableView, they would not be using some private API for cell separators, right?
I know you can get away without using actual separators, but adding one pixel line in the bottom of the cell. But I'm not a fan of this approach because
When a cell is selected/highlighted its separator and the separator of the previous cell are automatically hidden (see the second screenshot with "You've got to be crazy" selected). And this is
something I want UITableView to handle instead of doing myself if I use one-pixel line
(which is especially handy when cell separators do not extend all
the way to the edge of the table view, separators and selected cell background do not look nice together).
I would like to keep my cells as flat as possible for scrolling performance.
Also there is something in UITableView reference that makes me think that there is an easy way to get what I want:
In iOS 7 and later, cell separators do not extend all the way to the
edge of the table view. This property sets the default inset for all
cells in the table, much like rowHeight sets the default height for
cells. It is also used for managing the “extra” separators drawn at
the bottom of plain style tables.
Does somebody know how exactly to use these “extra” separators drawn at the bottom of plain style tables? Because this is exactly what I need.
I thought assigning separatorInsetto the UITableView, not UITableViewCell would do the trick, but it does not, the last cell is still missing its separator.
Right now I only see one option: to have a custom section footer to mimic the separator for the last cell. And this is not good, especially if you want to have an actual section footer using tableView:titleForFooterInSection: method.
This worked flawlessly for me to add a separator to the last cell. have fun!
self.tableView.tableFooterView = [[UIView alloc] init];
When you add headerView or footerView to your TableView, last separator line will disappear.
Example below will let you make workaround for showing separator on the last cell. The only thing you have to implement more is to make this separator disappearing after selecting cell, so behavior is the same like in the rest of cells.
For Swift 4.0
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let result = UIView()
// recreate insets from existing ones in the table view
let insets = tableView.separatorInset
let width = tableView.bounds.width - insets.left - insets.right
let sepFrame = CGRect(x: insets.left, y: -0.5, width: width, height: 0.5)
// create layer with separator, setting color
let sep = CALayer()
sep.frame = sepFrame
sep.backgroundColor = tableView.separatorColor?.cgColor
result.layer.addSublayer(sep)
return result
}
I just found something that works for me. In a few words: give your UITableView a tableFooterView and set its frame's height to 0. This makes an actual separator show, with the right insets.
In more details: if you are using the storyboard, drag a UIView to the bottom of your Table View (in the tree view on the left) so it shows just below Table View Cell, at the same hierarchical level. This creates a tableFooterView. Of course this can be done programmatically as well.
Then, in your UITableViewController's implementation:
UIView *footerView = self.tableView.tableFooterView;
CGRect footerFrame = footerView.frame;
footerFrame.size.height = 0;
[footerView setFrame:footerFrame];
Let me know if that works for you! It might also work for the first separator if you use a tableHeaderView instead, I haven't tried it though.
So here's a super simple solution in Swift 4 which works:
Inside override func viewDidLoad(){}, I simply implemented this line of code:
self.tableView.tableFooterView = UIView(frame: .zero)
Hence it ensures that only the last cell gets the separator inset.
This worked perfectly for me, hope it does for you too!
this will do exactly what you want .. even though the line will take the entire width of the cell:
in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.tableView.separatorColor = [UIColor redColor];
self.tableView.separatorInset = UIEdgeInsetsZero;
You can do something like this if you are not using sections:
- (void)viewDidLoad
{
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(insetLeftSide, 0, width - insetRightSide, 1)];
}
If you are using sections implement the footer in each section as a one point View in the methods
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
}
This will allow you to have a separator for your last cell which in fact is not a separator is a footer that you can play with it and make it look like a separator
Swift 3
I found this old issue, so I tried the same in Swift:
tableView.tableFooterView = UIView()
tableView.tableFooterView?.height = 0 // Maybe not necessary
But it lead to another problem (in my case). So I solved it differently. I added an extra cell at the end of this section, empty and with height equal to zero:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return previousNumberOfRows + 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.row == previousNumberOfRows ? 0 : previousCellHeight
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == items.count {
return UITableViewCell()
} else {
previousCellInitialization()
}
This is a less concise solution, but works in more cases, if you have multiple sections, existing footer view(s)...
I had a similar issue and found a workaround. Apple hides the last uitableviewcell separator and then displays it if you select the cell or if you call select and deselect on that cell.
So I taught the best is in - (void)layoutSubviews. The separator view is called _separatorView and it's a private property. Using the cell's selected / highlighted states you can come up with something like this:
- (void)layoutSubviews
{
// Call super so the OS can do it's layout first
[super layoutSubviews];
// Get the separator view
UIView *separatorView = [self valueForKey:#"_separatorView"];
// Make the custom inset
CGRect newFrame = CGRectMake(0.0, 0.0, self.bounds.size.width, separatorView.frame.size.height);
newFrame = CGRectInset(newFrame, 15.0, 0.0);
[separatorView setFrame:newFrame];
// Show or hide the bar based on cell state
if (!self.selected) {
separatorView.hidden = NO;
}
if (self.isHighlighted) {
separatorView.hidden = YES;
}
}
Something like this.
In iOS 8, if you have a plain style UITableView, and add a footer, the last separator is gone. However, you can easily recreate it by adding a custom separator view to the footer.
This example exactly mimics Today Widget separator style
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
//create footer view
let result = UIView()
result.frame.size.height = tableView.rowHeight
//recreate last cell separator, which gets hidden by footer
let sepFrame = CGRectMake(15, -0.5, tableView.frame.width, 0.5);
let vibrancyEffectView = UIVisualEffectView.init(effect: UIVibrancyEffect.notificationCenterVibrancyEffect())
vibrancyEffectView.frame = sepFrame
vibrancyEffectView.contentView.backgroundColor = tableView.separatorColor
result.addSubview(vibrancyEffectView)
return result
}
If you add an empty footer then the tableview will remove all the remaining line separators (for non-existent cells) but will still include the separator for the last cell:
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIView new];
}
I used the table view style "grouped" to add this line:
And furthermore it avoids sticking the last separator line to stick on the screen when scrolling out!
Works in iOS 7.x and 8.x (put it in cellForRowAtIndexPath):
(PS substitute "max elements of your datasource" with your array datasource count)
if (row == <max elements of your datasource>-1) {
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.contentView.frame.size.height-1, self.view.frame.size.width, 1)];/// change size as you need.
separatorLineView.tag = 666;
separatorLineView.backgroundColor = [UIColor colorWithRed: 204.0/255.0 green: 204.0/255.0 blue: 204.0/255.0 alpha:1.0];
UIView *separator = [cell.contentView viewWithTag:666];
// case of orientation changed..
if (separator.frame.size.width != cell.contentView.frame.size.width) {
[[cell.contentView viewWithTag:666] removeFromSuperview];
separator = nil;
}
if (separator==nil) [cell.contentView addSubview:separatorLineView];
}
This is definitely help. Working.
but set separator "none" from attribute inspector.
Write following code in cellForRowAtIndexPath method
if(indexPath.row==arrData.count-1){
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,
cell.contentView.frame.size.height - 1.0,
cell.contentView.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[cell.contentView addSubview:lineView];
}
The code below worked for me:
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 0.35)];
footerView.backgroundColor = [UIColor whiteColor];
CGRect frame = footerView.frame;
frame.origin.x = 15;
frame.size.width = frame.size.width - 15;
UIView *blackView = [[UIView alloc] initWithFrame:frame];
[blackView setBackgroundColor:[UIColor blackColor]];
blackView.alpha = 0.25;
[footerView addSubview:blackView];
tableView.tableFooterView = footerView;
Hope it works for you too.

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

Starting in iOS7, there is additional space at the top of my UITableView's which have a style UITableViewStyleGrouped.
Here is an example:
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
I was helped by the following:
YouStoryboard.storyboard > YouViewController > Attributes inspector > Uncheck - Adjust scroll view insets.
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.
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
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)
self.automaticallyAdjustsScrollViewInsets = NO;
try, you can deal with it!
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
}
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.
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.
Uncheck "Adjust Scroll View insets"
Another quick comment... even in XCode 6.1, there is a bug with vertical spaces appearing at the top of UIScrollViews, UITextViews 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.)
While using grouped TableView use this to avoid border cutting in viewWillAppear
self.tableView.contentInset = UIEdgeInsetsMake(-35, 0, 0, 0);
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.
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:
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.
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;
Storyboard:
Just uncheck: Adjust Scroll View Insets in View Controller's options
Code:
self.automaticallyAdjustsScrollViewInsets = false
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
}
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
}
}
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))
Simply add the following to your viewDidLoad in your VC:
self.automaticallyAdjustsScrollViewInsets = NO;
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;
}
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
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.
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.
Thanks to the answer by #Aurelien Porte. Here is my solution
Cause of this issue:-
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.
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
}
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];
}
}
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
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))
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.
2022 answer:
You just do this
tableView.contentInsetAdjustmentBehavior = .never
which is undocumented
Bizarre subtle gotchya ->
Tableviews have a very strange behavior these days:
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.
If you start NOT at the top of the screen, it won't do that, but
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()
}
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.
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.

Resources