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不工作 )
编辑:这是一个纯粹的接口生成器的方法:
注: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
解决方案:-
-(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 }
通过这种方式,您可以将layoutMargin
和separatorInset
设置为一次,而不是像每个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) } }
大多数答案显示分隔符插入和布局页边距被设置通过各种方法(即viewDidLayoutSubviews
, willDisplayCell
等)的单元格和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
willDisplayCell
和layoutMargins
:
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
被指示为属性,但试图将其作为属性(或方法)覆盖时会生成编译器错误。 并且为UITableViewCell
的layoutMargins
(或者,为UITableView
的layoutMargins
和separatorInset
设置外观代理)设置外观代理没有任何作用。
在第三层看到答案后,我试图找出在TableView和TableViewCell之间设置分隔符的关系,并做了一些测试。 这是我的结论:
-
我们可以考虑将单元格的分隔符设置为零必须分两步移动分隔符:第一步是将单元格的分隔符集合设置为零。 第二步是将单元格的marginlayout设置为零。
-
设置TableView的分隔符 , marginlayout可以影响单元格的分隔符 。 但是,从测试中,我发现TableView的分隔符似乎是无用的,TableView的marginlayout实际上可以影响单元格的marginlayout 。
-
设置Cell的PreservesSuperviewLayoutMargins = false,可以切断TableView对单元格的marginlayout效果。
-
解决方案之一:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = UITableViewCell() cell.preservesSuperviewLayoutMargins = false cell.separatorInset = UIEdgeInsetsZero cell.layoutMargins = UIEdgeInsetsZero return cell }
这是我的解决方案。 这适用于自定义单元格子类,只需将它们添加到子类。
-
- (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; }