我有一个应用程序,其中 UITableView
的分隔线内缩设置为自定义值 - 右边是 0
,左边也是 0
。这在 iOS 7.x
中完美地运行,然而在 iOS 8.0
中,我发现分隔线内缩被设置为右侧的默认值 15
。即使在 xib 文件中它被设置为 0
,它仍然显示不正确。
我如何去除 UITableViewCell
分隔线边距?
我有一个应用程序,其中 UITableView
的分隔线内缩设置为自定义值 - 右边是 0
,左边也是 0
。这在 iOS 7.x
中完美地运行,然而在 iOS 8.0
中,我发现分隔线内缩被设置为右侧的默认值 15
。即使在 xib 文件中它被设置为 0
,它仍然显示不正确。
我如何去除 UITableViewCell
分隔线边距?
iOS 8.0在单元格和表视图上引入了layoutMargins属性。
这个属性在iOS 7.0上不可用,所以在分配之前,您需要确保进行检查!
简单的解决方法是子类化您的单元格并覆盖布局边距属性,如@user3570727所建议的那样。 但是,您将失去任何系统行为(例如从安全区域继承边距),因此我不建议使用以下解决方案:
(ObjectiveC)
-(UIEdgeInsets)layoutMargins {
return UIEdgeInsetsZero // override any margins inc. safe area
}
(Swift 4.2):
override var layoutMargins: UIEdgeInsets { get { return .zero } set { } }
如果您不想覆盖该属性,或需要有条件地设置它,请继续阅读。
除了 layoutMargins
属性之外,苹果还为您的单元格添加了一个 属性,可以防止其继承您的表视图边距设置。当设置此属性时,您的单元格允许独立配置自己的边距而不受表视图的限制。将其视为覆盖操作。
该属性称为 preservesSuperviewLayoutMargins
,设置为 NO
将允许单元格的 layoutMargin
设置覆盖 TableView 上设置的任何 layoutMargin
。它既节省时间(您不必修改 Table View 的设置),也更简洁。请参考 Mike Abdullah 的答案以获取详细说明。
注意:以下是 Mike Abdullah 答案中所述的 单元格级边距设置的干净实现。将单元格的 preservesSuperviewLayoutMargins=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];
}
}
Swift 4:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// Remove seperator inset
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = .zero
}
// Prevent the cell from inheriting the Table View's margin settings
if cell.responds(to: #selector(setter: UITableViewCell.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
// Explictly set your cell's layout margins
if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
cell.layoutMargins = .zero
}
}
将单元格上的preservesSuperviewLayoutMargins
属性设置为NO,应该可以防止表格视图覆盖单元格边距。在某些情况下,它似乎不能正常工作。
如果所有尝试都失败了,您可以强制更改表格视图的边距:
-(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];
}
}
Swift 4:
func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Force your tableview margins (this may be a bad idea)
if tableView.responds(to: #selector(setter: UITableView.separatorInset)) {
tableView.separatorInset = .zero
}
if tableView.responds(to: #selector(setter: UITableView.layoutMargins)) {
tableView.layoutMargins = .zero
}
}
...然后你就完成了!这应该在iOS 7和8上起作用。
编辑: Mohamed Saleh提醒我注意可能发生的iOS 9变化。如果您想自定义插图或边距,则需要将表视图的cellLayoutMarginsFollowReadableWidth
设置为NO
。您的情况可能会有所不同,文档记录得不是很好。
此属性仅存在于iOS 9中,请在设置之前进行检查。
if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
myTableView.cellLayoutMarginsFollowReadableWidth = NO;
}
Swift 4:
if myTableView.responds(to: #selector(setter: self.cellLayoutMarginsFollowReadableWidth)) {
myTableView.cellLayoutMarginsFollowReadableWidth = false
}
(以上代码来自iOS 8 UITableView分隔符缩进0无效)
编辑:这是一个纯Interface Builder的方法:
注意:iOS 11会改变和简化很多此行为,将会有一个更新...
cell.preservesSuperviewLayoutMargins = NO
,否则在滚动一段时间后,插图仍会出现。(什么鬼?) - inorganikcell.preservesSuperviewLayoutMargins
后,这对我起作用了:- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
。 - mts哎呀!在你的Cell
子类中尝试做这个操作后:
- (UIEdgeInsets)layoutMargins
{
return UIEdgeInsetsZero;
}
或者将 cell.layoutMargins = UIEdgeInsetsZero;
进行设置也对我起到了作用。
separatorInset
也不起作用。表视图背景颜色也存在问题。这真的是令人头痛的事情。 - glasz在盲目尝试解决问题之前,让我们花点时间了解问题。
在调试器中快速查看会告诉您,分隔线是UITableViewCell
的子视图。似乎该单元格本身对这些行的布局负有相当大的责任。
iOS 8引入了“布局边距”的概念。默认情况下,视图的布局边距在所有侧面上为8pt
,并且它们从祖先视图中“继承”。
据我们所知,在布置其分隔线时,UITableViewCell
选择尊重左侧布局边距,并使用它来约束左插入。
把它们放在一起,要实现真正的零插入所需的是:
0
这么说吧,这是一个非常简单的任务:
cell.layoutMargins = UIEdgeInsetsZero;
cell.preservesSuperviewLayoutMargins = NO;
需要注意以下几点:
preservesSuperviewLayoutMargins
指定一个用户定义的运行时属性。preservesSuperviewLayoutMargins
,你可以配置祖先视图(例如表格)也具有 0
的左边距,但这似乎本质上更容易出错,因为你无法控制整个层次结构。0
,而让其他的保持不变可能会更加干净。[self.tableView setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 0)];
这一行代码,它将无法正常工作。 - davetw12UITableViewCell
的默认“separatorInset”,必须在UITableView
和UITableViewCell
上都将UIEdgeInsets
设置为零。如果你不做这两个操作,左侧缩进仍然大于零。我已经多次确认过这一点。 - davetw12preservesSuperviewLayoutMargins
是 NO
。 - esh我认为这是我在这里所问的同样问题:Remove SeparatorInset on iOS 8 UITableView for XCode 6 iPhone Simulator
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];
}
}
如果您在未检查layoutMargins
是否存在的情况下设置cell.layoutMargins = UIEdgeInsetsZero;
,则该应用程序将在iOS 7.x上崩溃。因此,在setLayoutMargins: UIEdgeInsetsZero
之前最好先检查layoutMargins
是否存在。
// 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代码的清洁,并且如果需要,您总是可以重写它。
iOS引入了layoutMargins属性,适用于单元格和表视图。
这个属性在iOS 7.0中不可用,所以在分配之前需要确保检查!
但是,苹果为您的单元格添加了一个名为“preservesSuperviewLayoutMargins”的属性,可以防止它继承您的表视图边距设置。 这样,您的单元格可以独立配置其自己的边距而不受表视图的影响。 将其视为覆盖。
此属性称为 preservesSuperviewLayoutMargins ,将其设置为NO可以允许您使用自己单元格的layouMargin设置覆盖表视图的layouMargin设置。 它既可以节省时间(您不必修改表视图的设置),而且更加简洁。 有关详细说明,请参阅Mike Abdullah的答案。
注意:这是正确的实现方式,如Mike Abdullah的答案所述;将单元格的preservesSuperviewLayoutMargins设置为NO将确保您的表视图不会覆盖单元格设置。
第一步-设置单元格边距:
/*
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
}
}
将单元格的preservesSuperviewLayoutMargins属性设置为NO 应该可以防止您的表视图覆盖单元格边距。在某些情况下,它似乎无法正常工作。
第二步——只有在所有其他方法都失败的情况下,您才可以强制更改您的表视图边距:
/*
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进行测试,我只需要使用这个说明的第一步骤。
只有在渲染的单元格下面没有填充的单元格时,才需要执行第二步骤,即如果表格比表格模型中的行数大。不执行第二步会导致不同的分隔符偏移量。
willDisplayCell
方法中检查选择器,因为该方法本身已经是iOS 8+的,并且不会从旧版本调用。 - Rivera在Swift中,这会稍微麻烦一些,因为layoutMargins
是一个属性,所以您必须重写getter 和 setter。
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
}
[UIColor clearColor]
,并自己绘制分隔符。这样你会更加灵活。 - freshkingUITableViewCellSeparatorStyle
默认值之一。即使被接受的答案在我看来也是一个非常肮脏的hack。 - Enrico Susatyo