分组的UITableview删除外部分隔线


77

我有一个以编程方式创建的分组UITableview。我也有一个以编程方式在tableview中填充的xib文件的单元格。到现在为止还挺好。但是我只想删除外部分隔线。我使用下面的代码,但是这次删除了所有分隔线。

self.tableView.separatorColor = [UIColor clearColor];

对于我的情况,这不是一个好选择。这是我想做的截图。

在此处输入图片说明


2
选项一:删除所有默认分隔符,并将UIViews作为伪分隔符添加到单元格中。希望有更好的选择。
Zsolt勋爵

这与上面的方法相同。就像我之前说过的,我只删除外部,即顶部和底部,而不是内部。如果我删除tableview中的所有分隔符,并在自定义单元格tableview的外观中添加新行,则仍然相同。
serhat sezer 2015年

4
解决方案是,将TableView用作Plain tableview,而不是分组。在“分组”中,将分隔符放在页眉和页脚上。
Iphonic

@iphonic,您的解决方案有效,谢谢:),但是普通的tableview仍然显示分隔符,即使它什么也没有。
li2

19
你是认真的,@ iphonic吗?!谁应该帮忙?li2?当某人使用分组的tableView时,最有可能的理由是。您是否看到分隔符不是分组表和普通表视图之间的唯一区别?
朱利安·F·韦纳特

Answers:


15

我刚刚制定了一个解决方案,就像单元格中contentView的一样UIView,所以我认为您可以专注于的底线contentView

这是我的代码:

首先,您必须清除分隔符

tableView.separatorColor = UIColor.clear

二,在cellForRowAt功能上:

let bottomBorder = CALayer()

bottomBorder.frame = CGRect(x: 0.0, y: 43.0, width: cell.contentView.frame.size.width, height: 1.0)
bottomBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).cgColor
cell.contentView.layer.addSublayer(bottomBorder)

在这里,您将看到如下界面:

在此处输入图片说明


21

这是我的解决方案:

self.tableView.separatorColor = self.tableView.backgroundColor

@xxtesaxx,您应该进行一次真正的测试


8
它会删除所有分隔符
Tikhonov Alexander

5
@Brook它将删除所有分隔符。如果您读了我的问题,我说过我只想删除“外”行。
serhat sezer

2
@serhatsezer是的,我读了你的问题,这是一个技巧性的解决方案,它使外线“消失”并保持分隔线可见。
布鲁克

@Brook但是,如果tableView背景色与分隔符颜色不同或TableView背景色与单元格颜色相同,则会出现问题。让我们说白色
。–

21

您甚至可以在带有静态单元格的分组UITableView中删除分隔符:

class CustomCell: UITableViewCell {

override func layoutSubviews() {
    super.layoutSubviews()
    for view in subviews where view != contentView {
        view.removeFromSuperview()
    }
}

但在iOS10中,也将在一个区域中删除单元格之间的线。
leo.tan

13

即使在2018年,Google仍将此页面作为该问题的最高结果。使用提供的任何答案,我在iOS 11中都没有运气,所以这是我想到的:

extension UITableViewCell {
    func removeSectionSeparators() {
        for subview in subviews {
            if subview != contentView && subview.frame.width == frame.width {
                subview.removeFromSuperview()
            }
        }
    }
}

现在,在任何UITableViewCell实例上调用.removeSectionSeparators()都会解决此问题。至少就我而言,节分隔符是唯一与单元格宽度相同的分隔符(因为其他分隔符都缩进了)。

剩下的唯一问题是从哪里调用它。您可能会认为willDisplayCell是最佳选择,但我发现初始调用发生在分隔符视图本身生成之前,因此没有骰子。

我最终在返回重新加载的单元格之前将其放入cellForRowAtIndexPath方法中:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyReusableIdentifier", for: indexPath)

    Timer.scheduledTimer(withTimeInterval: 0.15, repeats: false) { (timer) in
        cell.removeSectionSeparators()
    }

    return cell
}

感觉不那么优雅,但是我还没有遇到任何问题。

编辑:看起来我们也需要这个(对于重复使用的单元格):

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cell.removeSectionSeparators()
}

这是此代码的屏幕截图中的之前/之后:

之前 分离器拆卸之前

分离器拆卸后


1
就像魅力一样,谢谢。如果您在自定义类的布局子视图中调用它,效果会更好
TheJeff

1
这是我唯一可以从iOS 11开始使用的功能。谢谢。
jstr

9

检查视图层次结构之后,似乎每个UITableViewCell只有三个子视图:内容视图(UITableViewCellContentView)和两个分隔符视图(_UITableViewCellSeparatorView)。我不喜欢NSStrings中的动态类实例化(Apple😉也不喜欢)。然而,因为contentView一个UITableViewCell是不使用私有API的访问,该解决方案被证明是相当容易的。

这个想法只是要遍历的子视图UITableViewCell,并删除所有不是的视图contentView

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    let subviews = cell.subviews
    if subviews.count >= 3 {
        for subview in subviews {
            if subview != cell.contentView {
                subview.removeFromSuperview()
                break
            }
        }
    }
}

tableView(:willDisplayCell:forRowAtIndexPath:)在表格视图呈现期间多次调用,因此上文通过检查单元格具有多少个子视图来跟踪状态。如果它具有三个子视图,则两个分隔符均保持不变。它还仅删除一个分隔符,但是您可以通过删除来删除两个分隔符break。您还可以通过检查子视图的框架来指定是删除顶部分隔符还是底部分隔符。如果框架的y轴原点为0,则为顶部分隔符。如果不是0,那是底部。

希望这可以帮助!

Swift 4,Swift 4.2更新:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let subviews = cell.subviews
    guard subviews.count >= 3 else {
        return
    }

    for subview in subviews where NSStringFromClass(subview.classForCoder) == "_UITableViewCellSeparatorView" {
        subview.removeFromSuperview()
    }
}

1
谢谢,但是这种方法可能会在将来的iOS版本中出现问题?
serhat sezer

2
除非苹果将表视图的内部结构更改为具有多个内容视图,否则很有可能不会。如果您要更加小心,则可以选择使用NSStringFromClass这些值"_UITableViewCellSeparatorView""UITableViewCellContentView"与比较,然后将其删除。
Dan Loewenherz

2
Apple确实将tableViewCell视图的层次结构从iOS 7更改为iOS 8,这确实使我在项目上非常恼火,因为我使用了这样的代码,所以我建议不要那样做。
罗伯特·本特利

如果您担心过时或内部更改,#available对于任何大于当前版本的iOS版本,建议您将该属性与空主体一起使用。
Dan Loewenherz

8

用于删除每个部分的分隔线的顶部和底部。将此添加到您的静态单元格。

override func layoutSubviews() {
    super.layoutSubviews()

    //Get the width of tableview
    let width = subviews[0].frame.width

    for view in subviews where view != contentView {
        //for top and bottom separator will be same width with the tableview width
        //so we check at here and remove accordingly
        if view.frame.width == width {
            view.removeFromSuperview()
        }
    }
}

结果如下图

在此处输入图片说明


完美的答案,但对于非定制单元,我们可以实现吗?
Vishwas Singh,

1
这是唯一对我有用的解决方案。谢谢!
马特

6

这是一个确实很老的问题,它仍然是搜索如何删除每个部分的顶部和底部分隔符时在Google上的第一批条目之一。

经过一番调查,我发现,如果没有愚蠢的视图层次结构的骇客攻击,苹果公司将没有办法也没有意图使这种事情发生。

幸运的是,有一种绝对简单的方法可以实现这种外观:

在此处输入图片说明

我说的很简单,但是对于初学者来说,这可能很困难,因为缺乏对如何UITableView工作以及如何实现自己的单元的了解。让我尝试解释一下:

  1. 创建一个UITableViewCell子类
  2. 在您的单元中,创建一个@IBOutlet weak var separatorView: UIView!属性
  3. 在情节提要中,选择表格视图单元,然后选择您自己的单元作为备份单元的类。注意:您不必使用自定义样式。您仍然可以使用基本,字幕等。
  4. 设置你的UITableView小号Separator StyleNone隐藏默认的分隔符
  5. 将aUIView拖到您的单元格上并调整其大小,使其位于单元格的底部(或顶部)。使用Size InspectorsAutoresizing将其固定到开始/结束/底部,并为其提供弹性宽度(或“自动布局”,在这种情况下,就在顶部)
  6. 将视图连接到单元类的出口
  7. 在您的UITableViewDataSources中,根据cellForRowAtIndexPath:设置是部分的最后一行(如果视图是顶部,还是第一行),来设置isHidden自定义分隔符的属性indexPath.row

这里是一些示例代码:

class MyCell: UITableViewCell {
    @IBOutlet weak var separatorView: UIView!
}

class ViewController: UITableViewController {


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyCell
        cell.separatorView.isHidden = indexPath.row == 2
        return cell
    }

}

这里是一些屏幕截图:

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

是的,这是一项工作,但是编码时没有免费的方法。最后,我们是程序员,编写代码取决于我们。花5到10分钟的时间进行设置总比只复制粘贴一些骇人的代码更好,后者在将来苹果决定更改视图层次结构时可能无法继续工作。

编写此答案实际上比实现分隔符要花更多的工夫。我也一直在寻找一种简单快捷的解决方案,但最终没有一个值得我使用的好的解决方案。

我希望您也看到在循环运行时遍历单元格子视图以隐藏或什至在视图层次结构中从视图层次结构中删除视图时,也感到怀疑,这是苹果为您提供的简便,通用,稳定和面向未来的解决方案。只需要做7个小步骤,它们就很容易理解。


您的解决方案是否可与附件视图或标准UITableViewCell附件(V形,信息按钮等)一起使用?
Iur

由于您可以使用默认样式,而不必强制使用自定义样式,因此我认为使用默认附件应该没有问题。
xxtesaxx

我尝试了一下,但无法使分隔符出现在界面生成器的V形符号下。没尝试在设备上。这样做的原因-xcode仅允许将视图添加到单元格的contentView。雪佛龙是配件视图的一部分,显示在contentView旁边。
Iur

在这种情况下,您有多个选择。您可以简单地将分隔符视图扩展到右侧,这样一开始它就部分不可见。然后将内容视图向左推时,以前的不可见部分现在将可见。不是我的最爱,但它可以工作。然后,您可以将autolayout与自定义tableview单元格类结合使用。将分隔符固定到内容视图的底部和开头,但将单元格自身尾部固定。这样,即使内容视图收缩了,分隔符也将一直延伸到最后。
xxtesaxx

3

这是我最终想出的:

在此处输入图片说明

我找不到比这更好的方法了。但这对我很有帮助。上次尝试使用Xcode版本7.3.1(7D1014)。此过程通过情节提要进行。

基本上,我在UITableViewCell上添加了一个高度为0.5 pt的UIView,然后为该UIView设置了背景颜色。将父UITableView的Separator设置为None。

详细信息如下:

考虑到您已经设置了UITableViewCell,custom还是default。在第一阶段,将UITableView的分隔符设置为None。

在此处输入图片说明

接下来添加一个高度为1 pt的UIView并根据需要设置Background,在我的情况下为Red。

在此处输入图片说明

在此处输入图片说明

开始设置约束。问题是将UIView的高度设置为0.5磅。这是此工作流程的唯一问题问题。

高度为0.5 pt的UIView:

共享设置UIView高度0.5磅的方法。

首先(1)固定视图,然后(2)将高度设置为0.5。按Enter键。

在此处输入图片说明

最后,您的UIView将类似于以下内容。

在此处输入图片说明

除了这种方式,我无法将高度设置为0.5。


2

这里解决。这是针对静态单元格的。如果要动态,则只需重写“ count”。希望能帮助到你。

extension NSObject {
   var theClassName: String {
       return    NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
   }
}

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.separatorStyle = .None
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    let count = tableView.numberOfRowsInSection(indexPath.section)
    if ( indexPath.row != count - 1 ) {
        for view in cell.subviews {
            if view.theClassName == "_UITableViewCellSeparatorView" {
                view.backgroundColor = UIColors.redColor()
            }
        }
    }
}

1
这看起来是一个非常复杂的解决方案。如果您具有静态表格视图,为什么不将分隔符设置为none,并在想要的静态单元格中添加一些高度为1p的自定义视图?
xxtesaxx '17

老实说,我不是iOS框架内的调整的忠实拥护者,因为以后可以对其进行更改。因此,发布的应用程序可能存在问题。
serhat sezer

1

根据cell.separatorInset = UIEdgeInsetsMake()变通办法尝试了各种解决方案,但都无法正常工作。

对于我UITableViewStyleGrouped基于iOS11的项目,它做到了:

self.tableView.separatorColor = self.tableView.backgroundColor;

1

根据库克的答案,但没有计时器:

override func didAddSubview(_ subview: UIView) {
    super.didAddSubview(subview)
    if NSStringFromClass(subview.classForCoder) != "UITableViewCellContentView" && subview.frame.width == frame.width {
        subview.removeFromSuperview()
    }
}

只需将其添加到单元的子类中,就不需要其他任何东西了。适用于iOS 12。


1

iOS 13,迅捷5

在自定义单元格类中:

override func layoutSubviews(){
    super.layoutSubviews()

    for subview in subviews where (subview != contentView && abs(subview.frame.width - frame.width) <= 0.1 && subview.frame.height < 2) {
        subview.removeFromSuperview()                           //option #1 -- remove the line completely
        //subview.frame = subview.frame.insetBy(dx: 16, dy: 0)  //option #2 -- modify the length
    }
}

我要感谢@cook提供的此解决方案,因为它是基于它的。我的解决方案有一些问题:

  1. 它删除了默认的突出显示/选定的背景视图,所以我在子视图的高度上添加了额外的检查。
  2. 我把代码放进去了layoutSubviews(),还没有一个问题。
  3. 我在两个CGFloat之间实现了一个近似值,而不是使用equals运算符==,这听起来容易出错。

我在代码中添加了“选项#2”,因为这是我亲自寻找的解决方案(我想维护分隔符,但我希望它与常规单元格分隔符具有相同的缩进级别,在我的情况下,值16)。


0

我有一个类似的问题,我有一个带有自定义单元格的分组UITableView,所有这些都使用Interface Build设计为.xib文件。单元格具有白色背景,删除了默认的分隔符,并添加了我自己的分隔符。我还为每个部分定制了标题视图。我将这些“标题视图”的高度设置为44(可以是任何...)。我的部分之间有一个1点高度的视图,这看起来很奇怪。显然,即使我们将自定义高度指定为44,并且返回的自定义页眉视图具有白色(或某些具体的背景颜色),系统也会在各节之间添加一些清晰的背景视图。我们在透明视图后面看到的颜色实际上是表格视图背景的颜色。就我而言,表格视图和单元格都必须为白色,并将表格视图的背景设置为白色可以解决此问题(至少在视觉上是这样,但这还是我想要的)。第二种解决方案是保持Table View的样式简单,但是实现UITableView委托方法以返回2个或更多部分,并在需要时创建自定义标头。但这会使标题视图在滚动时一直停留在顶部一段时间(直到滚动),直到下一节的标题视图离它更近,然后它也开始上升(这可能不是您真正想要的,但是在那里可能是解决此问题的简便方法,但不确定)。


0

您可以使用以下方式访问视图

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

    let header = view as! UITableViewHeaderFooterView 
    header.backgroundView . .....

0

尝试此操作将删除顶部分隔线。

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.row == 0 && indexPath.section == 0) {
        for (UIView *view in  cell.subviews) {
            if ([NSStringFromClass([view class]) containsString:@"CellSeparator"]) {
                if (view.frame.origin.y == 0 && CGRectGetHeight(view.frame) < 1.01 ) { //Hide first UITableViewCellSeparatorView
                    NSLog(@"%s Remove View From Cell[Section:0 Row:0] for top border [%@]:%@",__FUNCTION__,NSStringFromClass([view class]),view);
                    view.hidden = YES; //Hide
                }
            }
        }
    }
}


0

iOS 10〜13只能删除节头脚线。

-(void)layoutSubviews{
    [super layoutSubviews];
    //for iOS10~iOS13: only remove section head foot line
    for (UIView * v in self.subviews) {
        if ( v != self.contentView &&
            (v.frame.size.width == self.frame.size.width)){
            [v removeFromSuperview];
        }
    }
}

如果要删除所有行:

    for (UIView * v in self.subviews) {
        if (v != self.contentView){
            [v removeFromSuperview];
        }
    }

0
 override func layoutSubviews() {
    super.layoutSubviews()
    subviews.filter { $0 != contentView && $0.frame.width == frame.width }.first?.removeFromSuperview()
}

3
请不要仅将代码发布为答案,还请提供解释代码的作用以及如何解决问题的方法。带有解释的答案通常会更有帮助,而且质量更好,并且更有可能引起反对。
马特D

-1

这是一个可在iOS 8和9上运行的Swift解决方案。

使用默认实现定义协议:

protocol CellSeparatorRemovable { }

extension CellSeparatorRemovable {
    func removeSeparatorLinesFromCell(cell: UITableViewCell, section: Int, row: Int, indexPath: NSIndexPath) {
        guard (section, row) == (indexPath.section, indexPath.row) else { return }

        for view in cell.subviews where view != cell.contentView {
            view.removeFromSuperview()
        }
    }
}

然后,无论您要在哪里使用它,都必须遵守CellSeparatorRemovable协议并从中调用其方法…willDisplayCell…

class SomeVC: UITableViewController, CellSeparatorRemovable {
    override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        removeSeparatorLinesFromCell(cell, section: 1, row: 1, indexPath: indexPath)
    }
}

这是一个最小的解决方案。如果要处理许多单元,则可能需要对其进行重构,以避免过多的递归和/或单元重用问题。


您好@Aaron我尝试了您的解决方案,但是分隔符仅在重新绘制单元格后消失(当您滚动并且它离开屏幕,然后您向后滚动时),但是第一次加载屏幕时,分隔符就在那里。我尝试了cell.setNeedsLayout()和cell.setNeedsDisplay()。知道如何解决吗?
PMT

1
最后,我不得不继承UITableViewCell并重写layoutSubviews()
PMT

2
破解视图层次结构可能不是一个好的解决方案。它可能随时更改。同样也不需要定制图纸。请查看我关于如何更好地解决OPs问题的答案
xxtesaxx
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.