Reputation: 28483
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
?
In iOS 11 and later:
tableView.contentInsetAdjustmentBehavior = .never
Upvotes: 736
Views: 332256
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
Reputation: 12287
You just do this
tableView.contentInsetAdjustmentBehavior = .never
which is undocumented
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 :/
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
Reputation: 369
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
}
Put this code, it will work
Upvotes: 5
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
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
Reputation: 383
For iOS 15, try below solution in viewDidLoad
:
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = .leastNormalMagnitude
}
Upvotes: 1
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
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
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
Reputation: 9462
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
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
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
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
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
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...
Upvotes: 0
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
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
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
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
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
Reputation: 123
set
override func viewDidLoad() {
self.tableView.delegate = self
self.tableView.dataSource = self
}
Upvotes: 0
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
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
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
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
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
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
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
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