UITableViewCell在iOS 11中使用separatorInset隐藏分隔符失败

这是我用来在iOS 11之前隐藏单个UITableViewCell的分隔符的代码:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { // Remove separator inset if ([cell respondsToSelector:@selector(setSeparatorInset:)]) { [cell setSeparatorInset:UIEdgeInsetsMake(0, tableView.frame.size.width, 0, 0)]; } // 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:UIEdgeInsetsMake(0, tableView.frame.size.width, 0, 0)]; } } } 

在这个例子中,分隔符在每个部分的第一行是隐藏的。 我不想完全摆脱分隔符 – 仅限于某些行。

在iOS 11中,上面的代码不起作用。 单元格的内容被完全推向右边。

有没有办法完成在iOS 11中隐藏单个UITableViewCell分隔符的任务?

让我先澄清一下,我知道我可以用下面的代码隐藏整个UITableView的分隔符(希望避免答案指示我这样做):

 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 

编辑:也要澄清下面的评论后,代码完全相同的事情,如果我包括setSeparatorInset行。 所以即使只有那一行,单元格的内容也会一直推到右边。

如果您不想在UITableViewCell添加自定义分隔符,我可以向您展示另一种需要考虑的解决方法。

怎么运行的

由于分隔符的颜色是在UITableView级别上定义的,因此没有明确的方法来根据UITableViewCell实例更改它。 这不是苹果打算的,你唯一能做的就是破解它。

您需要的第一件事是访问分隔视图。 你可以用这个小扩展来做到这一点。

 extension UITableViewCell { var separatorView: UIView? { return subviews .min { $0.frame.size.height < $1.frame.size.height } } } 

当你有权访问分隔视图时,你必须适当地configuration你的UITableView 。 首先,将所有分隔符的全局颜色设置为.clear (但不要禁用它们!)

 override func viewDidLoad() { super.viewDidLoad() tableView.separatorColor = .clear } 

接下来,为每个单元格设置分隔符的颜色。 你可以为每个人设置不同的颜色,取决于你。

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "SeparatorCell", for: indexPath) cell.separatorView?.backgroundColor = .red return cell } 

最后,对于该节中的每一行,将分隔符的颜色设置为.clear

 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if indexPath.row == 0 { cell.separatorView?.backgroundColor = .clear } } 

为什么它的作品

首先,我们来考虑一下UITableViewCell的结构。 如果你打印出你的单元格的subviews ,你会看到下面的输出。

 <UITableViewCellContentView: 0x7ff77e604f50; frame = (0 0; 328 43.6667); opaque = NO; gestureRecognizers = <NSArray: 0x608000058d50>; layer = <CALayer: 0x60400022a660>> <_UITableViewCellSeparatorView: 0x7ff77e4010c0; frame = (15 43.5; 360 0.5); layer = <CALayer: 0x608000223740>> <UIButton: 0x7ff77e403b80; frame = (0 0; 22 22); opaque = NO; layer = <CALayer: 0x608000222500>> 

正如你所看到的,有一个包含内容,分隔符和附件button的视图。 从这个angular度来看,您只需要访问分隔视图并修改其背景。 不幸的是,这并不容易。

让我们来看看在视图debugging器相同的UITableViewCell 。 正如你所看到的,有两个分隔符视图。 您需要访问调用willDisplay:时不存在的最下面一个。 这是第二个黑客部分发挥的地方。

表视图单元格的structorue

当你检查这两个元素时,你会看到第一个(从顶部)的背景颜色设置nil ,第二个背景颜色设置为你为整个UITableView指定的值。 在这种情况下,具有颜色的分离器覆盖没有颜色的分离器。

要解决这个问题,我们必须“扭转”这种情况。 我们可以将所有分隔符的颜色设置为.clear ,这将揭示我们有权访问的分隔符。 最后,我们可以将可访问分隔符的背景颜色设置为所需的颜色。

首先通过tableView.separatorStyle = .none隐藏所有分隔符。 然后修改你的UITableViewCell子类,如下所示:

 class Cell: UITableViewCell { var separatorLine: UIView? ... } 

将以下内容添加到tableView(_:cellForRowAt:)的方法主体中:

 if cell.separatorLine == nil { // Create the line. let singleLine = UIView() singleLine.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5) singleLine.translatesAutoresizingMaskIntoConstraints = false // Add the line to the cell's content view. cell.contentView.addSubview(singleLine) let singleLineConstraints = [singleLine.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 8), singleLine.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor), singleLine.topAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -1), singleLine.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: 0)] cell.contentView.addConstraints(singleLineConstraints) cell.separatorLine = singleLine } cell.separatorLine?.isHidden = [Boolean which determines if separator should be displayed] 

这个代码是在Swift中,所以你必须做Objective-C的翻译,并确保继续你的版本检查。 在我的testing中,我根本不需要使用tableView(_:willDisplayCell:forRowAt:) ,而是一切都在cellForRowAtIndexPath:方法中。

最好的方法IMO只是添加一个简单的UIView 1pt高度。 我写了下面的协议,使您可以在任何你喜欢的UITableViewCell中使用它:

 // Base protocol requirements protocol SeperatorTableViewCellProtocol: class { var seperatorView: UIView! {get set} var hideSeperator: Bool! { get set } func configureSeperator() } // Specify the separator is of a UITableViewCell type and default separator configuration method extension SeperatorTableViewCellProtocol where Self: UITableViewCell { func configureSeperator() { hideSeperator = true seperatorView = UIView() seperatorView.backgroundColor = UIColor(named: .WhiteThree) contentView.insertSubview(seperatorView, at: 0) // Just constraint seperatorView to contentView seperatorView.setConstant(edge: .height, value: 1.0) seperatorView.layoutToSuperview(.bottom) seperatorView.layoutToSuperview(axis: .horizontally) seperatorView.isHidden = hideSeperator } } 

你这样使用它:

 // Implement the protocol with custom cell class CustomTableViewCell: UITableViewCell, SeperatorTableViewCellProtocol { // MARK: SeperatorTableViewCellProtocol impl' var seperatorView: UIView! var hideSeperator: Bool! { didSet { guard let seperatorView = seperatorView else { return } seperatorView.isHidden = hideSeperator } } override func awakeFromNib() { super.awakeFromNib() configureSeperator() hideSeperator = false } } 

就这样。 您可以自定义任何UITableViewCell子类来使用分隔符。

从tableView中设置分隔符的可见性:willDisplayCell:forRowAtIndexPath通过:

 cell.hideSeperator = false / true 

实际上,当我使用UITableView时,我总是创build自定义的单元格类和分隔符,并且通常将自己的分隔符作为具有高度1和左右约束的UIView,在您的情况下,请执行以下步骤:1.创build自定义单元格。 2.添加UIView作为分隔符。 3.将此分隔符链接到您的自定义类。 4.将hideSeparator方法添加到您的类中。

 -(void)hideSeparator{ self.separator.hidden == YES; } 

5.隐藏你想要的任何单元格的分隔符。

希望能解决你的问题。