为什么在iOS7中UITableViewStyleGrouped样式的UITableView顶部会有额外的填充?

728

iOS7开始,在我的UITableView(样式为UITableViewStyleGrouped)的顶部有额外的空白。

这里是一个例子:

enter image description here

表格视图从第一个箭头开始,有35像素的无法解释的填充,然后绿色的标题是viewForHeaderInSection返回的UIView(其中的section为0)。

有人能解释一下这35像素的量来自哪里,以及我如何在不切换到UITableViewStylePlain的情况下摆脱它吗?


更新(答案):

在iOS 11及更高版本中:

tableView.contentInsetAdjustmentBehavior = .never

你正在使用最新的iOS 7吗?这些不一致性中的某些类型(但不是全部,也许不包括此问题)在后期的开发预览中已经得到了解决。我应该知道:我拖延了很久,其中一些问题消失了。 - Dan Rosenstark
简短的回答是,这个额外的填充可能是由于表视图标题(而不是分区标题)造成的,而且 UITableView 不喜欢被分配一个高度为 0.0 的标题。请查看 https://dev59.com/cmMk5IYBdhLWcg3w5Bzy#31223403 获取更多详细信息。 - Aurelien Porte
40
这段代码的意思是:将表格视图的表头设置为一个高度极小的空白视图。在此提醒一下,如果您在矩形的高度中使用0.0f,则会被忽略掉,因此我们需要使用最接近零的CGFloat(至少这对我来说是“可行”的...但不是理想的解决方案)。 - Alejandro Iván
2
@AlejandroIván,你的评论让我今晚感到很开心。我有一个带有分组原型的tableView。我使用numberSections = data.count并设置numberRows = 1。我设置了heightForFooterInSection来在每个之间留出干净的空间,但由于某种原因,出现了一个空白的tableHeaderView。 - Ryan Alexander
1
如果 #available(iOS 15.0, *) { table.sectionHeaderTopPadding = 0 } 把这段代码放进去就可以了。 - Vinayak
显示剩余6条评论
78个回答

869

以下内容帮助了我:

YouStoryboard.storyboard > YouViewController > 属性检查器 > 取消勾选 - 调整滚动视图插图。

输入图片描述


42
我认为这是移除填充的正确方法,而不是调整edgeInset值。 - Hgeg
24
对我来说这个方法不起作用——我的导航栏是不透明的,在使用该方法后,内容会被推到它下面。 - slycrel
6
对我没用;唯一有效的方法是将设置更改为“纯文本”而不是“分组”。 - shim
29
我遇到了一个容器视图中TableViewController的问题。我不得不将这个属性设置在包含容器视图的视图控制器上,而不是嵌入的TableViewController本身。这样它才能正常工作。 - Andy Mortimer
5
这个选项存在的纯粹目的是为了让人烦恼吗? - Ian Warburton
显示剩余18条评论

346

我进一步尝试了一下,发现将tableView的tableHeaderView = nil会导致这种副作用。

因为我的tableView具有动态出现的tableHeaderView,当我需要隐藏tableHeaderView时,我不是执行self.tableView.tableHeaderView = nil;,而是执行:

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

我认为这种解决方案比设置某种不太明确的contentInset.top更好,因为我也动态使用contentInset.top。每当我重新计算contentInset.top时,必须记得减去额外的35像素,这很繁琐。


4
好的解决方案!确实,按照你的代码,你需要将其设置为0.01f才能摆脱默认的表视图标题视图。 - Simone Manganelli
2
顺便说一句,在界面构建器中也可以通过拖放完成这个操作。无论如何,谢谢! :) - Rudolf Adamkovič
9
您做得非常好,应该得到一枚奖章。 - Vaibhav Gautam
8
请记住,如果表视图的顶部高度为0.01f,则下面的所有单元格都将错位(第一个单元格的Y原点为0.01,下一个单元格的原点为cell_height + 0.01等),因此这些单元格的内容会错位。(在模拟器中打开调试>颜色不对齐的图像以自行查看。)您不想这样做。 - Simon Whitaker
4
最好使用UITableViewHeaderFooterView而不是UIView。 并且在理论上,CGFLOAT_MIN0.01f的作用相同,但更好。 - Jaybo
显示剩余8条评论

195
尝试更改UITableViewUIScrollView继承的contentInset属性。
self.tableView.contentInset = UIEdgeInsetsMake(-20, 0, 0, 0);

这是一个解决方法,虽然有点折中,但它确实可行。


7
"contentTableView.contentInset = UIEdgeInsetsMake(-20, 0, -20, 0);" 对我来说效果最好,因为顶部和底部都有多余的20像素。 - Brian
1
虽然这种“蛮力”解决方案可行,但我认为底部的那些(特别是自动调整插图)应该排名更高。 - eladleb
4
这句话的意思是“这个方法不太正规,但iOS系统很垃圾,所以我们能做的也只有这么多了。” - AlexK

180

如果您在视图控制器中为IOS 7分配表视图,您可以查看

self.edgesForExtendedLayout = UIRectEdgeNone;

你的问题似乎和我的相似

更新:

iOS 9.x 中的 Swift:

self.edgesForExtendedLayout = UIRectEdge.None

Swift 3:

self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0)

3
我对我的简单UITableView进行了操作。问题出在我的UITableView位于UINavigationController内的UIViewController上,导致表格内容下移了44个点,因此初始内容没有显示在navBar后面。虽然我的布局并不需要这样,但这仍然引起了问题。最终我改变了我的代码,使用了automaticallyAdjustsScrollViewInsets也能够解决问题。 - DBD
此属性仅适用于嵌入在容器中(例如UINavigationController)的视图控制器。窗口的根视图控制器不会对此属性做出反应。此属性的默认值为all。我觉得默认值应该是0?这有什么优势呢? - Desh__
5
更优雅的使用 Swift 3: edgesForExtendedLayout = [] - Dave Batton
你好@yeahdixon, 你用什么软件制作粉色箭头?提前感谢。 - iArezki

140
self.automaticallyAdjustsScrollViewInsets = NO;

尝试一下,你可以处理它!


这在iOS 7.0中隐藏tableHeaderView很好用,但它不支持较旧的版本。 - Brian
在iOS 7下表现良好。 - StackRunner
4
重要提示:请确保在容器视图控制器中执行此操作,如果您的UITableView放置在一个控制器上,然后再将该控制器嵌入到另一个控制器中,请在嵌入顶层控制器中执行此操作,而不是直接在您放置UITableView的控制器中执行(这里由自动布局处理)。 - James Stone
这比“取消勾选调整滚动视图插图”更好。因为有时我们不使用Storyboard来构建我们的UI。 - JW.ZG
3
这在iOS 11.0中已被弃用。Xcode会发出警告。请改用以下方法,在您不想自动调整插图的滚动视图上:self.tableView.contentInsetAdjustmentBehavior = .never - David Topolansky
显示剩余2条评论

91

iOS 15的解决方案:

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

整个项目中修复:

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

更多细节: iOS 15中UITableView头部上方的额外填充

注意: 这仅适用UITableView.Style.plain


1
太好了,谢谢!其他的答案都没解决我的问题。 - Joel
1
谢谢!!它完美地运行。 - Ganesh G
1
这个。谢谢。我为了弄清楚这个问题而苦思冥想了一段时间。我将手机升级到了iOS 15,然后我的应用程序的任何新版本都表现出了这种行为。但是,我在应用商店中现有的版本没有这个问题。再次感谢。 - Dan
无上下文类型,无法解析成员“sectionHeaderTopPadding”的引用。 - Ahmadreza
1
这是纯金! - Rafael Nobre

81

您可以检测您的应用程序是否在运行iOS7或更高版本,并在您的表视图委托中添加这两个方法(通常在您的UIViewController代码中)

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

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

这可能不是一个优雅的解决方案,但对我而言有效。

Swift版本:

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

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

1
这对我有效。UITableView 在顶部添加空间有许多不同的原因。具体而言,与 OP 相关的问题仅发生在分组样式表视图中。这个解决方案修复了这个问题。 - RajV
5
你可以使用CGFLOAT_MIN代替0.001,它会给你一个最小的CGFloat绝对值。 - KaroCodes
2
这是正确的答案,因为真正的特性是填充仅存在于分组样式表视图中,并且如果您指定标题/页脚,则会被忽略。 - Jakub Truhlář
这应该被标记为正确答案。有一个委托方法可以重写并回答这个问题。如果你已经看到了所有的hack,请至少先尝试这个。尝试使用以下代码:-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { //return CGFLOAT_MIN; return 30.0f; } - Matthew Ferguson
不错! 作为奖励,如果您想在顶部添加一个小标题并在分组部分之间添加更多内容,可以使用以下代码:override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return section == 0 ? 14 : 24 } - Freek Sanders
这是最佳解决方案,因为使用普通样式会改变页眉/页脚的行为。谢谢! - Bruno Muniz

60

我已经找到了原始错误的原因,并创建了一个展示它的示例项目。我认为这是iOS7的一个bug。

iOS7之后,如果你创建一个分组样式的UITableView,但在第一次布局时没有设置代理,然后设置了代理并调用reloadData,顶部将会出现一个永远不会消失的35像素的空间。

请参见我制作的展示此错误的项目:https://github.com/esilverberg/TableViewDelayedDelegateBug

特别是这个文件:https://github.com/esilverberg/TableViewDelayedDelegateBug/blob/master/TableViewDelayedDelegateBug/ViewController.m

如果第24行是激活的,则:

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

如果第27行被激活而第24行被注释掉,则在顶部会多出35像素的空间。

self.tableView.delegate = self;

顶部没有空间。就像tableView在设置委托并调用reloadData后没有重新绘制自己一样,似乎缓存了某个结果。


21
即使存在代理方法,但如果代理的 tableView:heightForHeaderInSection:tableView:heightForFooterInSection: 返回0,你仍会遇到这个问题。对以上协议方法进行实现并返回0.01f,可以解决这个问题。 - John Estropia
1
是的!我尝试了三种所谓的解决方案,而这个是最好的!太棒了,谢谢:D - Henrik Erlandsson
有人报告了一个错误,因为我认为这不是预期的行为。 - Pushparaj
太好了!这在iOS 9中仍然存在(我们没有使用XIB),但在init上设置委托解决了间距问题(不是在loadView或viewDidLoad中)。谢谢! - John Stricker
2
设置 header 的 estimatedHeight 对我很有帮助。 - Viktor
显示剩余2条评论

50

取消勾选“调整滚动视图插图”

输入图片描述


我需要在另一个视图控制器中使用此选项,显然当我创建一个新的VC时,更改也会带过来。感谢您! - David
耶!成功了,只需要将它放在 ContainerView 中就可以了! - Felipe FMMobile

46

另一个快速评论... 即使在XCode 6.1中,UIScrollViewsUITextViewsUITableViews顶部会出现垂直空白的bug。

enter image description here

有时,解决此问题的唯一方法是进入Storyboard并拖动有问题的控件,使其不再是页面上的第一个子视图。

enter image description here

(感谢Oded指引我走向正确方向... 我发表这个评论,只是为了添加一些截图,以演示症状和解决方法。)


1
请注意,如果您在页面上有一个UITextView作为第一个子控件,则此错误(或问题)也会在iOS 8中发生...因此这不仅仅是UITableView的问题。 - Mike Gledhill
1
在所有的解决方案中,只有这个hack对我起作用了。一个奇怪的修复方法来解决一个奇怪的bug。我曾经在UITableview中遇到过这个问题。 - Mesbah
4
非常感谢您!这是我唯一可行的解决方案。 - user139816
1
我很惊讶18个月过去了,读者们仍然在投票支持这个答案。难道苹果还没有解决这个问题吗?! - Mike Gledhill
1
我确认这个问题在Xcode 8.3.2(Swift 3)中仍然不可思议地发生。修复方法有效!非常感谢! - Claus
显示剩余12条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接