UITableViewCell分隔符在iOS7中消失

我只有在iOS 7 UITableView有一些奇怪的问题。

UITableViewCellSeparator消失在第一行之上和最后一行之下。 有时候在select行或者一些滚动动作之后就会出现。

在我的情况下, tableView是从Storyboard加载UITableViewStylePlain风格。 这个问题肯定不在UITableViewCellSeparatorStyle ,它不会从默认的UITableViewCellSeparatorStyleSingleLine更改。

正如我在苹果开发者论坛在这里和这里 )阅读,其他人有这样的问题,并find一些解决方法,例如:

 Workaround: disable the default selection and recreate the behaviour in a method trigged by a tapGestureRecognizer. 

但我仍然在寻找这种分离奇怪行为的原因。

有任何想法吗?

更新:正如我在XCode 5.1 DP和iOS 7.1 beta中看到的,Apple试图解决这个问题。 现在分隔符是根据需要显示的,有时在最后一行之后,刷新后,但不是在创buildtableview之后。

我倾销受影响的单元格的子视图层次结构,发现_UITableViewCellSeparatorView设置为隐藏。 难怪没有显示!

我覆盖layoutSubviews在我的UITableViewCell子类和现在的分隔符都可靠地显示:

Objective-C

 - (void)layoutSubviews { [super layoutSubviews]; for (UIView *subview in self.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { subview.hidden = NO; } } } 

Swift

 override func layoutSubviews() { super.layoutSubviews() guard let superview = contentView.superview else { return } for subview in superview.subviews { if String(subview.dynamicType).hasSuffix("SeparatorView") { subview.hidden = false } } } 

这里提出的其他解决scheme并不一致对我来说或似乎笨重(添加自定义1 px页脚视图)。

这对我工作:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // fix for separators bug in iOS 7 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 

我也有丢失分隔符的问题,我发现问题只发生在heightForRowAtIndexPath 返回一个十进制数 。 解:

 override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return ceil(yourHeight) // Ceiling this value fixes disappearing separators } 

您是否尝试在浅灰色背景颜色的表头和页脚中添加高度为1的UIView? 基本上它会嘲笑第一个和最后一个分隔符。

@samvermette

我通过使用这个委托方法解决了这个问题。 现在它不闪烁:

 -(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { // fix for separators bug in iOS 7 tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; } -(void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { // fix for separators bug in iOS 7 tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; } 

我们在应用程序中遇到了这个问题。 当用户select一个单元格时,新的表格视图被压入导航控制器堆栈,然后当用户popup时,分隔符丢失。 我们通过把[self.tableView deselectRowAtIndexPath:indexPath animated:NO];解决了它[self.tableView deselectRowAtIndexPath:indexPath animated:NO];didSelectRowAtIndexPath表中查看委托方法。

这里有一个比较简单(虽然有点麻烦)的解决方法,如果你需要的话,在数据重载和默认animation完成后,尝试select和取消select单元格。

只需添加:

 [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; 

我发现最简单的解决方法是在重新加载单元之后,重新加载上面的单元格:

 if (indexPath.row > 0) { NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section]; [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationNone]; } 

适用于iOS 8和iOS 9(testing版1)的简单而干净的解决scheme

这是一个简单, 干净和非侵入性的解决方法。 它涉及调用将修复分隔符的类别方法。

您只需沿着单元格的层次结构并取消隐藏分隔符。 喜欢这个:

 for (UIView *subview in cell.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { subview.hidden = NO; } } 

我推荐的是把这个添加到UITableViewCell上的类别,如下所示:

 @interface UITableViewCell (fixSeparator) - (void)fixSeparator; @end @implementation UITableViewCell (fixSeparator) - (void)fixSeparator { for (UIView *subview in self.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { subview.hidden = NO; } } } @end 

由于分隔符可能会消失在与当前所选单元格不同的单元格中,因此在表视图中的所有单元格上调用此修补程序可能是个好主意。 为此,您可以将类添加到UITableView,如下所示:

 @implementation UITableView (fixSeparators) - (void)fixSeparators { for (UITableViewCell *cell in self.visibleCells) { [cell fixSeparator]; } } @end 

有了这个,您可以在导致它们消失的操作之后-fixSeparatos在您的tableView上调用-fixSeparatos 。 在我的情况下,它是在调用[tableView beginUpdates][tableView endUpdates]

正如我在开始时所说的,我已经在iOS 8和iOS 9上testing过了。我认为它甚至可以在iOS 7上运行,但我没有办法在那里尝试。 正如你可能知道的那样,这确实会弄乱单元的内部,所以它可能会在以后的版本中停止工作。 而苹果理论上可能(0.001%的几率)因为这个原因拒绝你的应用程序,但我看不出他们甚至可以找出你在那里做什么(检查一个类的后缀不能被静态分析器检测到坏,国际海事组织)。

根据@ ortwin-gentz的评论,这个解决scheme适用于iOS 9。

 func fixCellsSeparator() { // Loop through every cell in the tableview for cell: UITableViewCell in self.tableView.visibleCells { // Loop through every subview in the cell which its class is kind of SeparatorView for subview: UIView in (cell.contentView.superview?.subviews)! where NSStringFromClass(subview.classForCoder).hasSuffix("SeparatorView") { subview.hidden = false } } } 

(SWIFT代码)

在我的tableView的某些方法中调用endUpdates()之后,我使用了fixCellsSeparator()函数,例如:

 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { // Perform some stuff // ... self.tableView.endUpdates() self.fixCellsSeparator() } 

我希望这个解决scheme对于某个人来说是有帮助的!

airpaulg的答案的补充。

所以基本上必须实现两个UITableDelegate方法。 这是我的解决scheme,可以在iOS7和iOS6上使用。

 #define IS_OS_VERSION_7 (NSFoundationVersionNumber_iOS_6_1 < floor(NSFoundationVersionNumber)) #define UIColorFromRGB(hexRGBValue) [UIColor colorWithRed:((float)((hexRGBValue & 0xFF0000) >> 16))/255.0 green:((float)((hexRGBValue & 0xFF00) >> 8))/255.0 blue:((float)(hexRGBValue & 0xFF))/255.0 alpha:1.0] 

//如果它们没有覆盖整个屏幕,这将隐藏单元格下面的空表格

 - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { UIView *view = nil; if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */) { CGFloat height = 1 / [UIScreen mainScreen].scale; view = [[UIView alloc] initWithFrame:CGRectMake(0., 0., 320., height)]; view.backgroundColor = UIColorFromRGB(0xC8C7CC); view.autoresizingMask = UIViewAutoresizingFlexibleWidth; } else { view = [UIView new]; } return view; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */) { return 1 / [UIScreen mainScreen].scale; } else { // This will hide the empty table grid below the cells if they do not cover the entire screen return 0.01f; } } 

这为我解决了这个问题:

确保单元格的clipsToBounds设置为YES,但单元格的contentView设置为NO。 另外设置cell.contentView.backgroundColor = [UIColor clearColor];

似乎这个问题在如此多的情况下显现出来。

对我来说,这与细胞select有关。 我不知道为什么,也没有时间深入研究它,但是我可以说,当我将单元格的selectionStyle设置为none时,它就开始发生了。 即:

 //This line brought up the issue for me cell.selectionStyle = UITableViewCellSelectionStyleNone; 

我尝试使用上面的一些委托方法,打开和closurestableViewseparatorStyle属性,但他们似乎没有做任何事情来解决我的问题。

我需要的全部原因是因为我甚至不需要细胞select。

所以,我find了适合我的东西。 我只是禁用UITableViewselect:

 tableView.allowsSelection = NO; 

希望这可以帮助别人,如果你不需要细胞select。

我试了很多build议来解决,但无法解决这个问题。最后,我决定自定义分隔线如下:

 func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { var lineView = UIView(frame: CGRectMake(20, cell.contentView.frame.size.height - 1.0, cell.contentView.frame.size.width - 20, 1)) lineView.backgroundColor = UIColor(red: 170.0/255.0, green: 170.0/255.0, blue: 170.0/255.0, alpha: 1) cell.contentView.addSubview(lineView) } 

P / S:定制在willDisplayCell NOT cellForRowAtIndexPath

相当令人惊讶的是,来回更改单元格的separatorInset值似乎正在工作:

 NSIndexPath *selectedPath = [self.controller.tableView indexPathForSelectedRow]; [self.controller.tableView deselectRowAtIndexPath:selectedPath animated:YES]; UITableViewCell *cell = [self.controller.tableView cellForRowAtIndexPath:selectedPath]; UIEdgeInsets insets = cell.separatorInset; cell.separatorInset = UIEdgeInsetsMake(0.0, insets.left + 1.0, 0.0, 0.0); cell.separatorInset = insets; 

我也有这个不一致的分隔线显示在我的UITableView底部的问题。 使用自定义页脚视图,我可以创build一个类似的行,并将其显示在潜在的现有页面上(有时会丢失)。

这个解决scheme的唯一问题是苹果可能会改变一天的线路厚度

 - (UIView*) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { float w = tableView.frame.size.width; UIView * footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, w, 1)]; footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; footerView.clipsToBounds=NO; UIView* separatoraddon = [[UIView alloc] initWithFrame:CGRectMake(0, -.5, w, .5)]; separatoraddon.autoresizingMask = UIViewAutoresizingFlexibleWidth; separatoraddon.backgroundColor = tableView.separatorColor; [footerView addSubview:separatoraddon]; return footerView; } - (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 1; } 

我已经解决了把这些代码行放在tableview更新的地方:

 self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None; self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine; 

例如,在我的情况下,我把它们放在这里:

 tableView.beginUpdates() tableView.insertRowsAtIndexPaths(insertIndexPaths, withRowAnimation: UITableViewRowAnimation.Fade) tableView.endUpdates() self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None; self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine; 

在进行单元更新之前,您需要删除单元格select。 然后你可以恢复select。

 NSIndexPath *selectedPath = [self.tableview indexPathForSelectedRow]; [self.tableview deselectRowAtIndexPath:selectedPath animated:NO]; [self.tableview reloadRowsAtIndexPaths:@[ path ] withRowAnimation:UITableViewRowAnimationNone]; [self.tableview selectRowAtIndexPath:selectedPath animated:NO scrollPosition:UITableViewScrollPositionNone]; 

要解决上述问题,请在viewDidLoad中添加空的页脚。

 UIView *emptyView_ = [[UIView alloc] initWithFrame:CGRectZero]; emptyView_.backgroundColor = [UIColor clearColor]; [tableView setTableFooterView:emptyView_]; 

请勿在viewForFooterInSection委托方法中使用上述行。 意思是不实现viewForFooterInSection方法。

扩大airpaulg的答案,因为它不完全适用于我..

我还必须实现heightforfooter方法来获得高度

然后我注意到lightgraycolor太黑了。 我通过抓取tableview的当前分隔符颜色来解决这个问题,并使用它:

UIColor *separatorGray = [self.briefcaseTableView separatorColor]; [footerSeparator setBackgroundColor:separatorGray];

我也在我们的项目中遇到了这个问题。 我的表视图有一个tableFooterView可以做到这一点。 我发现最后一行下面的分隔符会出现,如果我删除tableFooterView。

是什么让我不同的是重新加载底部分隔线不会出现的行:

 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]; [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

我以另一种方式解决了这个问题:添加一个高度为0.5px的图层,其颜色为浅灰色,放入tableview.tableFooterView作为其子图层。

代码就像这样:

 UIView *tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 70)]; CALayer *topSeperatorLine = [CALayer layer]; topSeperatorLine.borderWidth = 0.5f; topSeperatorLine.borderColor = [UIColor lightGrayColor].CGColor; topSeperatorLine.frame = CGRectMake(0, 0, 320, 0.5f); [tableFooterView.layer addSublayer:topSeperatorLine]; self.tableView.tableFooterView = tableFooterView; 

在你的UITableViewCell子类中实现layoutSubviews并添加:

 - (void)layoutSubviews{ [super layoutSubviews] for (UIView *subview in self.contentView.superview.subviews) { if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) { CGRect separatorFrame = subview.frame; separatorFrame.size.width = self.frame.size.width; subview.frame = separatorFrame; } } } 

正如别人提到的那样,这个问题似乎以各种方式performance出来。 我通过以下解决方法解决了我的问题:

 [tableView beginUpdates]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; [tableView endUpdates]; 

通过回答和解决scheme,我提出了这样的观察:

这似乎是在iOS 7和8的问题。我注意到从viewDidLoad方法中的代码中select单元格时的问题,所以:

1)解决方法是这样做的viewDidAppear:如果有人不介意呈现视图和select单元格之间的明显延迟

2) 第二个解决scheme为我工作,但代码看起来有点脆弱,因为它基于UITableViewCell的内部实现

3)添加自己的分隔符似乎是目前最灵活和最好的,但需要更多的编码:)

viewWillAppear设置样式为我工作。

由于这仍然是IOS 8的一个问题,我将在Swift中添加我的解决scheme。 将tableview分隔线设置为none。 然后将此代码添加到cellForRowAtIndexPath委托方法。 它会添加一个很好的分隔符。 if语句允许决定哪些单元应该有分隔符。

  var separator:UIView! if let s = cell.viewWithTag(1000) { separator = s } else { separator = UIView() separator.tag = 1000 separator.setTranslatesAutoresizingMaskIntoConstraints(false) cell.addSubview(separator) // Swiper constraints var leadingConstraint = NSLayoutConstraint(item: separator, attribute: .Leading, relatedBy: .Equal, toItem: cell, attribute: .Leading, multiplier: 1, constant: 15) var heightConstraint = NSLayoutConstraint(item: separator, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0.5) var bottomConstraint = NSLayoutConstraint(item: cell, attribute: .Bottom, relatedBy: .Equal, toItem: separator, attribute: .Bottom, multiplier: 1, constant:0) var trailingConstraint = NSLayoutConstraint(item: cell, attribute: .Trailing, relatedBy: .Equal, toItem: separator, attribute: .Trailing, multiplier: 1, constant: 15) cell.addConstraints([bottomConstraint, leadingConstraint, heightConstraint, trailingConstraint]) } if indexPath.row == 3 { separator.backgroundColor = UIColor.clearColor() } else { separator.backgroundColor = UIColor.blackColor() } 

这是我解决这个问题的方法。 插入您的单元格后,重新加载该部分。 如果重新加载整个部分对您来说过于密集,只需重新加载上面和下面的indexPath。

 [CATransaction begin]; [CATransaction setCompletionBlock:^{ // Fix for issue where seperators disappear [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone]; }]; [self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade]; [CATransaction commit]; 

遇到类似的问题,我发现另一个很好的解决scheme,尤其是如果你的dataSource不是很大,当你实现-(void)scrollViewDidScroll:(UIScrollView *)scrollView方法重新加载-(void)scrollViewDidScroll:(UIScrollView *)scrollView ,这里是一个例子:

 -(void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == self.tableView1) { [self.tableView1 reloadData]; } else { [self.tableView2 reloadData]; } } 

你也可以重新加载不可见的数据基于可见的dataSource,但是这需要更多的黑客攻击。

请记住,这个委托函数属于UITableViewDelegate协议!

希望能帮助到你!