esilver
esilver

Reputation: 28483

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:

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

Upvotes: 736

Views: 332256

Answers (30)

Kumar Lav
Kumar Lav

Reputation: 409

This one line of code will make you happy.

override func viewDidLoad() {
        super.viewDidLoad()
        if #available(iOS 15.0, *) {
            tableView.sectionHeaderTopPadding = CGFloat(0)
        }
    }

Upvotes: 15

Fattie
Fattie

Reputation: 12287

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

Upvotes: 12

Vinayak
Vinayak

Reputation: 369

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

Put this code, it will work

Upvotes: 5

Levan Karanadze
Levan Karanadze

Reputation: 471

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.

Upvotes: 113

Idrees Ashraf
Idrees Ashraf

Reputation: 1383

enter image description here

Setting content Insets to Never solved the problem for me.

Upvotes: 0

shndrs
shndrs

Reputation: 11

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

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

Upvotes: 1

Mahesh K
Mahesh K

Reputation: 383

For iOS 15, try below solution in viewDidLoad:

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

Upvotes: 1

Kang Developer
Kang Developer

Reputation: 83

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

Upvotes: -1

Vipul Kumar
Vipul Kumar

Reputation: 961

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

Upvotes: 29

Hasan
Hasan

Reputation: 11

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
}

Upvotes: 1

Nik
Nik

Reputation: 9462

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

Upvotes: 1

Narendra Prajapati
Narendra Prajapati

Reputation: 79

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.sstatic.net/fjxOV.png

Upvotes: 5

Serg Smyk
Serg Smyk

Reputation: 663

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

Upvotes: 2

Starsky
Starsky

Reputation: 2048

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.

Upvotes: 2

Ludovik Lejeune
Ludovik Lejeune

Reputation: 41

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

Upvotes: 4

pandu
pandu

Reputation: 47

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

Upvotes: 0

Kiran Jasvanee
Kiran Jasvanee

Reputation: 6564

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

Upvotes: 1

Saeed Ir
Saeed Ir

Reputation: 2332

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

Upvotes: 13

vinny
vinny

Reputation: 370

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.

Upvotes: 1

Hapeki
Hapeki

Reputation: 2193

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.

Upvotes: 3

MobileMon
MobileMon

Reputation: 8661

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

Upvotes: 1

Ch M Zia Ur Rehman
Ch M Zia Ur Rehman

Reputation: 123

set
  override func viewDidLoad() {
  self.tableView.delegate = self
  self.tableView.dataSource = self
}

Upvotes: 0

c0d3p03t
c0d3p03t

Reputation: 1674

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.

Upvotes: 0

F. Morales
F. Morales

Reputation: 477

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
}

Upvotes: 4

coolbeet
coolbeet

Reputation: 1665

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.

Upvotes: 1

Mr.Javed Multani
Mr.Javed Multani

Reputation: 13294

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
    }

Upvotes: 3

nvrtd frst
nvrtd frst

Reputation: 6332

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

Upvotes: 197

Sujan
Sujan

Reputation: 147

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.

Upvotes: 1

LightMan
LightMan

Reputation: 3575

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
}

Upvotes: 81

Aks
Aks

Reputation: 1587

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

Upvotes: 4

Related Questions