iOS 8 UITableView分离器嵌入0不工作

我有一个应用程序,UITableView'的分隔符被设置为自定义值 - 右边0,左边0。这在 "iOS 7.x "中运行良好,但在 "iOS 8.0 "中,我看到分隔器的嵌入被设置为右侧的默认值 "15"。即使在xib文件中设置为`0',它仍然显示不正确。

我如何删除UITableViewCell的分隔符?

对该问题的评论 (4)
解决办法

**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'设置覆盖你的表视图上的任何layoutMargin'。这既节省了时间(你不需要修改表视图的设置),又更简洁。请参考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];
    }
}

快速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];
    }
} 

快速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中,所以在设置前一定要检查。

Swift 4:

if myTableView.responds(to: #selector(setter: self.cellLayoutMarginsFollowReadableWidth)) {
    myTableView.cellLayoutMarginsFollowReadableWidth = false
}

(以上代码来自https://stackoverflow.com/questions/25770119/ios-8-uitableview-separator-inset-0-not-working/32860532#32860532)

编辑:这里有一个纯界面生成器的方法:

![TableViewAttributesInspector][1]![TableViewCellSizeInspector][2]

注意:iOS 11改变并简化了这一行为的大部分内容,即将进行更新...

评论(22)

在玩过之后,要么在你的Cell子类中这样做。

- (UIEdgeInsets)layoutMargins
{
    return UIEdgeInsetsZero;
}

或者设置cell.layoutMargins = UIEdgeInsetsZero;为我解决了问题。

评论(12)

让我们在盲目地冲进去试图修复它之前,先花点时间了解一下这个问题。

在调试器中快速戳一下会告诉你,分隔线是UITableViewCell的子视图。 看来,单元格本身对这些线条的布局承担了相当大的责任。

iOS 8引入了布局边距的概念。 默认情况下,一个视图'的布局边距在所有边上都是8pt,它们'是从祖先视图中*继承的。

据我们所知,在布局其分隔线时,UITableViewCell选择尊重左侧布局边距,用它来约束左侧插页。

综合这些,要想实现真正零的插页,我们需要。

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

这样说来,要实现这个任务很简单。

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

需要注意的事情。

  • 这段代码每个单元格只需要运行一次(毕竟你只是在配置单元格的属性),而且你选择执行它的时候也没有什么特别的地方。 做你认为最干净的事情。
  • 遗憾的是,这两个属性都不能在Interface Builder中配置,但如果需要的话,你可以为preservesSuperviewLayoutMargins指定一个用户定义的运行时属性。
  • 显然,如果你的应用也针对早期的操作系统版本,你需要避免执行上述代码,直到在iOS 8及以上版本上运行。
  • 与设置preservesSuperviewLayoutMargins相比,你可以配置祖先视图(如表格)也有0左边距,但这似乎本质上更容易出错,因为你不控制整个层次结构。
  • 如果只将左边距设置为0,其他的都不设置,可能会更简洁一些。
  • 如果你想在"extra" 分隔符,UITableView在普通样式表的底部绘制,我猜想这也需要在表层指定相同的设置(还没试过这个!)。
评论(14)

我相信这也是我在这里提出的问题:https://stackoverflow.com/questions/25762723/remove-separatorinset-on-ios-8-uitableview-for-xcode-6-iphone-simulator

iOS 8中,所有继承自UIView的对象都有一个新属性。所以,在iOS7.x中设置SeparatorInset的方案将无法去除你在iOS8中看到的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上应用程序会崩溃。

评论(2)

您可以在应用程序启动时(在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'的代码干净,如果你想的话,可以随时覆盖它。

评论(2)

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

这个属性在iOS 7.0中是不可用的,所以你需要在分配它之前确认一下!不过,苹果已经为你的单元格和表格视图添加了属性,叫做preservesSuperviewLayoutMargins

然而,Apple已经为你的单元格添加了一个名为preservesSuperviewLayoutMargins的**属性,这将防止它继承你的表视图'的边距设置。 这样,你的单元格就可以独立于表视图配置自己的边距。 可以把它看作是一个覆盖。

这个属性叫做preservesSuperviewLayoutMargins,将它设置为NO可以让你用自己单元格的layoutMargin设置覆盖你的Table View'的layoutMargin设置。 这既节省了时间(你不必修改表视图的设置),也更简洁。 详细解释请参考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进行测试,在我的情况下,我只需要使用本解释的第一步。

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

评论(2)

在Swift中,这稍微有点麻烦,因为layoutMargins是一个属性,所以你必须覆盖getter setter。

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

这将有效地使layoutMargins成为只读的,在我的例子中,这很好。

评论(4)

对于iOS 9,你需要添加。

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

详情请见【问题】(https://stackoverflow.com/a/31538250/3151066)。

评论(1)

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
评论(1)

斯威夫特。

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()            //  UITableViewCell {
     ...

    if cell.respondsToSelector("setSeparatorInset:") {
        cell.separatorInset = UIEdgeInsetsZero
    }
    if cell.respondsToSelector("setLayoutMargins:") {
        cell.layoutMargins = UIEdgeInsetsZero
    }

    return cell
}
评论(0)

我通过这样做,让它成功了。

tableView.separatorInset = UIEdgeInsetsZero;
tableView.layoutMargins = UIEdgeInsetsZero;
cell.layoutMargins = UIEdgeInsetsZero;
评论(0)

至于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];
        }
}
评论(0)

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
    }
}
评论(0)

经过大量的调查...

这是唯一能完全控制这些东西的方法(我可以找到)。

要完全控制每个单元格的分隔符插入和布局边距。 在你的 "UITableviewDelegate "上的 "willDisplayCell "方法中这样做。

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
评论(1)

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

override func awakeFromNib() {
    super.awakeFromNib()

    self.layoutMargins = UIEdgeInsetsZero
    self.separatorInset = UIEdgeInsetsZero
}

通过这种方式,你只需设置layoutMarginseparatorInset一次,而不是像上面大多数答案所建议的那样,为每个willDisplayCell设置。

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

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

评论(0)

对我来说,简单的一句话就搞定了

cell.layoutMargins = UIEdgeInsetsZero
评论(1)

只要加上下面的代码就可以解决这个程序。

祝您好运!

-(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];
       }

}

-(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];
       }

}
评论(0)

卢卡兹用Swift回答。

    // 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
    }
评论(0)

这是我在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边缘/边距调整都是在tableView:willDisplayCell:forRowAtIndexPath:方法中完成的,而不需要将不必要的代码塞进tableView:cellForRowAtIndexPath:中。

顺便说一下,我只设置了单元格的左分隔符Inset/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)
        }
    }
评论(2)

大多数答案都显示单元格和tableviews的分隔符插入和布局边距被设置在各种方法上(即viewDidLayoutSubviewswillDisplayCell等),但我发现只要把这些放在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];
评论(0)