iOS 8的UITableView分隔符插入0不工作

我有一个应用程序的UITableView的分隔符插入设置为自定义值 – 右0 ,左0 。 这在iOS 7.x是完美的,但是在iOS 8.0我发现分隔符插入的默认值是15 。 即使在xib文件中设置为0 ,它仍然显示不正确。

如何删除UITableViewCell分隔边距?

iOS 8.0在单元格和表格视图中引入了layoutMargins属性。

此属性在iOS 7.0上不可用,因此您需要确保在分配之前进行检查!

此外,苹果已添加一个属性到您的单元格,将阻止它继承您的表视图的边距设置。 设置此属性时,您的单元格可以独立于表格视图来配置自己的边距。 把它看作是一个重载。

这个属性被称为preservesSuperviewLayoutMargins ,将其设置为NO将允许单元格的layoutMargin设置覆盖在您的TableView上设置的任何layoutMargin 。 这既节省时间( 你不必修改表视图的设置 ),而且更简洁。 请参阅Mike Abdullah的答案以获得详细的解释。

注意:下面是一个干净的实施细胞级别的保证金设置 ,如迈克阿卜杜拉的答案中所表达的。 设置你的单元格的保留SuperviewLayoutMargins = NO将确保你的表视图不会覆盖单元格设置。 如果您确实希望整个表格视图具有一致的边距,请相应地调整您的代码。

设置您的单元格边距:

 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { // Remove seperator inset if ([cell respondsToSelector:@selector(setSeparatorInset:)]) { [cell setSeparatorInset:UIEdgeInsetsZero]; } // Prevent the cell from inheriting the Table View's margin settings if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) { [cell setPreservesSuperviewLayoutMargins:NO]; } // Explictly set your cell's layout margins if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } } 

将单元格上的保留视图布局放置属性设置为“否” 防止表格视图覆盖单元格边距。 在某些情况下,它似乎不能正常工作。

如果全部失败,您可能会蛮力强制您的表视图边距:

 -(void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; // Force your tableview margins (this may be a bad idea) if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) { [self.tableView setSeparatorInset:UIEdgeInsetsZero]; } if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) { [self.tableView setLayoutMargins:UIEdgeInsetsZero]; } } 

…你去了! 这应该在iOS 7和8上工作。

编辑: Mohamed Saleh带来了我的注意在iOS 9可能的变化。您可能需要设置表视图的cellLayoutMarginsFollowReadableWidth如果您要自定义cellLayoutMarginsFollowReadableWidth或页边距。 你的里程可能会有所不同,这是没有记录得很好。

此属性仅在iOS 9中存在,因此请务必在设置之前进行检查。

 if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { myTableView.cellLayoutMarginsFollowReadableWidth = NO; } 

(上面的代码从iOS 8 UITableView分隔符插入0不工作 )

编辑:这是一个纯粹的接口生成器的方法:

TableViewAttributesInspector TableViewCellSizeInspector

注:iOS 11更改和简化了这种行为的大部分,即将更新…

精氨酸! 在你的Cell子类中玩这个之后,

 - (UIEdgeInsets)layoutMargins { return UIEdgeInsetsZero; } 

或者设置cell.layoutMargins = UIEdgeInsetsZero; 给我修好了

让我们先花一点时间来理解这个问题,然后再盲目收费来修复它。

在调试器中快速浏览会告诉你,分隔线是UITableViewCell子视图。 电池本身似乎对这些线路的布局承担了相当的责任。

iOS 8引入了布局边距的概念。 默认情况下,视图的布局边界是8pt ,并且从祖先视图继承

最好的情况是,在布局分隔线时, UITableViewCell选择尊重左侧布局边距,使用它来限制左侧插入。

把所有这些放在一起,为了达到真正意义上的零度,我们需要:

  • 将左侧布局页边距设置为0
  • 停止任何继承的边距覆盖

像这样做,这是一个非常简单的任务:

 cell.layoutMargins = UIEdgeInsetsZero; cell.preservesSuperviewLayoutMargins = NO; 

注意事项:

  • 这个代码只需要在每个单元格中运行一次(毕竟你只是配置了单元格的属性),当你选择执行它时没有什么特别之处。 做什么似乎对你最干净。
  • 可悲的是,在Interface Builder中都不能配置属性,但是如果需要,您可以指定一个用户定义的运行时属性,用于preservesSuperviewLayoutMargins SupersviewLayoutMargins。
  • 很显然,如果你的应用程序定位在早期的操作系统版本,那么你需要避免执行上面的代码,直到运行在iOS 8及更高版本上。
  • 可以配置祖先视图(例如表格)以使其具有0左边距,而不是设置preservesSuperviewLayoutMargins视图布局preservesSuperviewLayoutMargins ,因为您无法控制整个层次结构,所以这似乎更具有错误倾向性。
  • 将左边距设置为0而将其余的设置为0 ,可能会稍微清洁一些。
  • 如果你想在UITableView在普通样式表底部绘制的“额外”分隔符上有一个0插入,我猜这将需要在表级别指定相同的设置(还没有尝试过这个!)

我相信这是我在这里问的同一个问题: 删除iOS 8上的SeparatorInset UITableView for XCode 6 iPhone模拟器

iOS 8中 ,所有从UIView继承的对象都有一个新属性。 因此,在iOS 7.x中设置SeparatorInset的解决方案将无法删除您在iOS 8中的UITableView上看到的空白区域。

新的属性被称为“ layoutMargins ”。

 @property(nonatomic) UIEdgeInsets layoutMargins Description The default spacing to use when laying out content in the view. Availability iOS (8.0 and later) Declared In UIView.h Reference UIView Class Reference 

iOS 8 UITableView setSeparatorInset:UIEdgeInsetsZero setLayoutMargins:UIEdgeInsetsZero

解决方案:-

 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{ if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) { [tableView setSeparatorInset:UIEdgeInsetsZero]; } if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) { [tableView setLayoutMargins:UIEdgeInsetsZero]; } if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } } 

如果你设置cell.layoutMargins = UIEdgeInsetsZero; 而不检查layoutMargins存在,应用程序将在iOS 7.x上崩溃。 所以,最好的方法是在setLayoutMargins:UIEdgeInsetsZero之前检查layoutMargins存在。

您可以在应用程序启动时(在UI加载之前)使用UIAppearance,将其设置为默认的全局设置:

 // iOS 7: [[UITableView appearance] setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine]; [[UITableView appearance] setSeparatorInset:UIEdgeInsetsZero]; [[UITableViewCell appearance] setSeparatorInset:UIEdgeInsetsZero]; // iOS 8: if ([UITableView instancesRespondToSelector:@selector(setLayoutMargins:)]) { [[UITableView appearance] setLayoutMargins:UIEdgeInsetsZero]; [[UITableViewCell appearance] setLayoutMargins:UIEdgeInsetsZero]; [[UITableViewCell appearance] setPreservesSuperviewLayoutMargins:NO]; } 

这样,你保持你的UIViewController的代码干净,并且可以随时覆盖它,如果你想。

Swift版本

iOS在单元格和表格视图中引入了layoutMargins属性。

此属性在iOS 7.0中不可用,因此您需要确保在分配之前进行检查!

但是,苹果已经添加了名为preservesSuperviewLayoutMargins属性到您的单元格,这将阻止它继承您的表视图的边距设置。 这样,您的单元格可以独立于表视图配置自己的边距。 把它看作是一个重载。

这个属性被称为preservesSuperviewLayoutMargins ,将其设置为NO可以让您使用自己的单元格的layoutMargin设置覆盖TableView的layoutMargin设置。 这既节省时间( 你不必修改表视图的设置 ),而且更简洁。 请参阅Mike Abdullah的答案以获得详细的解释。

注意:正如迈克·阿卜杜拉(Mike Abdullah)的回答所表达的那样,这是正确的,不那么杂乱的实现。 设置你的单元格的保留SuperviewLayoutMargins =否将确保你的表视图不会覆盖单元格设置。

第一步 – 设置您的单元格边距:

 /* Tells the delegate that the table view is about to draw a cell for a particular row. */ override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { // Remove separator inset if cell.respondsToSelector("setSeparatorInset:") { cell.separatorInset = UIEdgeInsetsZero } // Prevent the cell from inheriting the Table View's margin settings if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") { cell.preservesSuperviewLayoutMargins = false } // Explictly set your cell's layout margins if cell.respondsToSelector("setLayoutMargins:") { cell.layoutMargins = UIEdgeInsetsZero } } 

将单元格上的保留视图布局放置属性设置为“否” 防止表格视图覆盖单元格边距。 在某些情况下,似乎不能正常工作。

第二步 – 只有在全部失败的情况下,才可能暴力破坏你的表格视图边距:

 /* Called to notify the view controller that its view has just laid out its subviews. */ override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // Force your tableview margins (this may be a bad idea) if self.tableView.respondsToSelector("setSeparatorInset:") { self.tableView.separatorInset = UIEdgeInsetsZero } if self.tableView.respondsToSelector("setLayoutMargins:") { self.tableView.layoutMargins = UIEdgeInsetsZero } } 

…你去了! 这应该适用于iOS 8以及iOS 7。

注意:使用iOS 8.1和7.1进行测试,在我的情况下,我只需要使用这个解释的第一步。

第二步只有在渲染的单元格下面有未填充的单元格时才需要。 如果表格大于表格模型中的行数。 不做第二步会导致不同的分隔符偏移量。

在Swift中,它比较麻烦,因为layoutMargins是一个属性,所以你必须重写getter setter。

 override var layoutMargins: UIEdgeInsets { get { return UIEdgeInsetsZero } set(newVal) {} } 

这将有效地使layoutMargins只读,这在我的情况是好的。

对于iOS 9,您需要添加:

 if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { myTableView.cellLayoutMarginsFollowReadableWidth = NO; } 

有关更多详细信息,请参阅问题 。

Swift 2.0扩展

我只是想分享我从tableview单元格分隔符中删除边距的扩展。

 extension UITableViewCell { func removeMargins() { if self.respondsToSelector("setSeparatorInset:") { self.separatorInset = UIEdgeInsetsZero } if self.respondsToSelector("setPreservesSuperviewLayoutMargins:") { self.preservesSuperviewLayoutMargins = false } if self.respondsToSelector("setLayoutMargins:") { self.layoutMargins = UIEdgeInsetsZero } } } 

在上下文中使用:

  let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell cell.removeMargins() return cell 

迅速:

 override func viewDidLoad() { super.viewDidLoad() if self.tableView.respondsToSelector("setSeparatorInset:") { self.tableView.separatorInset = UIEdgeInsetsZero } if self.tableView.respondsToSelector("setLayoutMargins:") { self.tableView.layoutMargins = UIEdgeInsetsZero } self.tableView.layoutIfNeeded() // <--- this do the magic } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { ... if cell.respondsToSelector("setSeparatorInset:") { cell.separatorInset = UIEdgeInsetsZero } if cell.respondsToSelector("setLayoutMargins:") { cell.layoutMargins = UIEdgeInsetsZero } return cell } 

我是这样做的:

 tableView.separatorInset = UIEdgeInsetsZero; tableView.layoutMargins = UIEdgeInsetsZero; cell.layoutMargins = UIEdgeInsetsZero; 

对我来说简单的工作就是做这个工作

 cell.layoutMargins = UIEdgeInsetsZero 

至于什么cdstamper建议,而不是表视图,在单元格的layoutSubview方法中添加下面的行适用于我。

 - (void)layoutSubviews { [super layoutSubviews]; if ([self respondsToSelector:@selector(setSeparatorInset:)]) [self setSeparatorInset:UIEdgeInsetsZero]; if ([self respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) { [self setPreservesSuperviewLayoutMargins:NO];; } if ([self respondsToSelector:@selector(setLayoutMargins:)]) { [self setLayoutMargins:UIEdgeInsetsZero]; } } 

(经过很多调查,这是处理这个恕我直言的正确方法)

要完全控制每个单元格上的分隔符插页和布局页边距。 你只需要在你的tableview代表这个代码。 iOS8或iOS9上不需要其他任何东西。

 func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { cell.layoutMargins = UIEdgeInsetsZero cell.contentView.layoutMargins = UIEdgeInsetsMake(0, 10, 0, 10) cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0) } 

单元格对象控制着分隔符,而contentView则控制其他的一切。 如果您的分隔符插入空间显示在意想不到的颜色,这应该解决它:

 cell.backgroundColor = cell.contentView.backgroundColor 

Swift 3.0例子:

 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // removing seperator inset if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) { cell.separatorInset = .zero } // prevent the cell from inheriting the tableView's margin settings if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) { cell.preservesSuperviewLayoutMargins = false } // explicitly setting cell's layout margins if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) { cell.layoutMargins = .zero } } 

Swift for iOS 8中使用自定义UITableViewCell简单解决方案

 override func awakeFromNib() { super.awakeFromNib() self.layoutMargins = UIEdgeInsetsZero self.separatorInset = UIEdgeInsetsZero } 

通过这种方式,您可以将layoutMarginseparatorInset设置为一次,而不是像每个willDisplayCell一样对上面的答案进行建议。

如果你正在使用自定义的UITableViewCell这是正确的地方。 否则,你应该在tableView:cellForRowAtIndexPath做到这一点。

只是另一个提示:你不需要设置preservesSuperviewLayoutMargins = false因为默认值已经是NO

只需添加下面的代码即可解决这个程序。

祝你好运!

 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if ([cell respondsToSelector:@selector(setSeparatorInset:)]) { [cell setSeparatorInset:UIEdgeInsetsZero]; } if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } } 

使用下面的代码片段,避免IOS 8和7中的UITableView不需要的填充问题。

 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{ if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) { [tableView setSeparatorInset:UIEdgeInsetsZero]; } if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) { [tableView setLayoutMargins:UIEdgeInsetsZero]; } if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } } 

这是在Swift中为我工作的代码:

 override func viewDidLoad() { super.viewDidLoad() ... if tableView.respondsToSelector("setSeparatorInset:") { tableView.separatorInset = UIEdgeInsetsZero } } func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) { if cell.respondsToSelector("setSeparatorInset:") { cell.separatorInset.left = CGFloat(0.0) } if tableView.respondsToSelector("setLayoutMargins:") { tableView.layoutMargins = UIEdgeInsetsZero } if cell.respondsToSelector("setLayoutMargins:") { cell.layoutMargins.left = CGFloat(0.0) } } 

这对我来说(现在)是最清洁的,因为在tableView:willDisplayCell:forRowAtIndexPath:方法中完成所有单元格/ tableView边缘/边距调整,而无需在tableView:cellForRowAtIndexPath: tableView:willDisplayCell:forRowAtIndexPath:不必要的代码。

顺便说一句,我只是设置单元格的左边的separatorInset / layoutMargins,因为在这种情况下,我不想搞乱我在单元格中设置的约束。

代码更新到Swift 2.2:

  override func viewDidLoad() { super.viewDidLoad() if tableView.respondsToSelector(Selector("setSeparatorInset:")) { tableView.separatorInset = UIEdgeInsetsZero } } override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) { if cell.respondsToSelector(Selector("setSeparatorInset:")) { cell.separatorInset.left = CGFloat(0.0) } if tableView.respondsToSelector(Selector("setLayoutMargins:")) { tableView.layoutMargins = UIEdgeInsetsZero } if cell.respondsToSelector(Selector("setLayoutMargins:")) { cell.layoutMargins.left = CGFloat(0.0) } } 

大多数答案显示分隔符插入和布局页边距被设置通过各种方法(即viewDidLayoutSubviewswillDisplayCell等)的单元格和tableviews,但我发现只是把这些在cellForRowAtIndexPath工程很好。 看起来像最干净的方式。

 // kill insets for iOS 8 if ([[UIDevice currentDevice].systemVersion floatValue] >= 8) { cell.preservesSuperviewLayoutMargins = NO; [cell setLayoutMargins:UIEdgeInsetsZero]; } // iOS 7 and later if ([cell respondsToSelector:@selector(setSeparatorInset:)]) [cell setSeparatorInset:UIEdgeInsetsZero]; 

每次单元格滚动时(使用willDisplayCell ),我都会建议在cellForRowAtIndexPath:执行一次,而不是更新preservesSuperviewLayoutMargins willDisplayCelllayoutMargins

 override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) cell.preservesSuperviewLayoutMargins = false cell.layoutMargins = UIEdgeInsetsZero return cell } 

卢卡斯斯在斯威夫特的回答:

  // iOS 7: UITableView.appearance().separatorStyle = .SingleLine UITableView.appearance().separatorInset = UIEdgeInsetsZero UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero // iOS 8: if UITableView.instancesRespondToSelector("setLayoutMargins:") { UITableView.appearance().layoutMargins = UIEdgeInsetsZero UITableViewCell.appearance().layoutMargins = UIEdgeInsetsZero UITableViewCell.appearance().preservesSuperviewLayoutMargins = false } 

在iOS8中:

将此添加到我的UITableViewCell子类:

 - (UIEdgeInsets)layoutMargins { return UIEdgeInsetsZero; } 

这和“tableView:cellForRowAtIndexPath”或“tableView:willDisplayCell”:

 [editCell setSeparatorInset:UIEdgeInsetsZero]; 

为我工作。

这是一个简单的方法来全局删除插入。

UITableViewCell+Extensions.swift

 import UIKit extension UITableViewCell { override public var layoutMargins: UIEdgeInsets { get { return UIEdgeInsetsZero } set { } } } 

AppDelegate application:didFinishLaunchingWithOptions: ::

  UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero 

您可能认为a)也只是在扩展中重写separatorInset ,或者b)设置layoutMargins的外观代理。 都不会工作。 即使separatorInset被指示为属性,但试图将其作为属性(或方法)覆盖时会生成编译器错误。 并且为UITableViewCelllayoutMargins (或者,为UITableViewlayoutMarginsseparatorInset设置外观代理)设置外观代理没有任何作用。

在第三层看到答案后,我试图找出在TableView和TableViewCell之间设置分隔符的关系,并做了一些测试。 这是我的结论:

  1. 我们可以考虑将单元格的分隔符设置为零必须分两步移动分隔符:第一步是将单元格的分隔符集合设置为零。 第二步是将单元格的marginlayout设置为零。

  2. 设置TableView的分隔符marginlayout可以影响单元格的分隔符 。 但是,从测试中,我发现TableView的分隔符似乎是无用的,TableView的marginlayout实际上可以影响单元格的marginlayout

  3. 设置Cell的PreservesSuperviewLayoutMargins = false,可以切断TableView对单元格的marginlayout效果。

  4. 解决方案之一:

     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = UITableViewCell() cell.preservesSuperviewLayoutMargins = false cell.separatorInset = UIEdgeInsetsZero cell.layoutMargins = UIEdgeInsetsZero return cell } 

这是我的解决方案。 这适用于自定义单元格子类,只需将它们添加到子类。

  1.  - (UIEdgeInsets)layoutMargins { return UIEdgeInsetsMake(0, 10, 0, 10); } 

2。

 self.separatorInset = UIEdgeInsetsMake(0, 10, 0, 10); 

而且您可以自定义分隔符的位置,而不要求设计师为您绘制一个便利的方法……….

 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // ... Get the cell cell.separatorInset = UIEdgeInsetsMake(0.f, 20.f, 0.f, [UIScreen mainScreen].bounds.size.width - 20); // others return cell; } 

对于任何想要隐藏分隔符的特定单元格。

以比最投票答案更紧凑的方式…

 - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if ([cell respondsToSelector:@selector(setSeparatorInset:)] && [cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)] && [cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setSeparatorInset:UIEdgeInsetsZero]; [cell setPreservesSuperviewLayoutMargins:NO]; [cell setLayoutMargins:UIEdgeInsetsZero]; } 

}

添加这个片段,简单优雅的Swift在iOS8中适用于我:)

  // tableview single line func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { cell.preservesSuperviewLayoutMargins = false cell.layoutMargins = UIEdgeInsetsZero } 

这在iOS 8和iOS 9中完美适用于我。

对于OBJ-C

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) { [tableView setSeparatorInset:UIEdgeInsetsZero]; } if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) { [tableView setLayoutMargins:UIEdgeInsetsZero]; } if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } return cell; }