IOS7中消失的 UITableViewCell 分离器

我有一些奇怪的问题与 UITableView只在 iOS7。

UITableViewCellSeparator在第一行上方和最后一行下方消失。有时在选择行或一些滚动操作之后,它会出现。

在我的情况下,tableView是从 Storyboard加载的 UITableViewStylePlain样式。问题肯定不在 UITableViewCellSeparatorStyle中,它没有从默认的 UITableViewCellSeparatorStyleSingleLine更改。

正如我在 < em > Apple Dev Forums (翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳)上读到的,其他人也有这样的问题,并找到了一些变通方法,例如:

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

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

有什么想法吗?

更新: 正如我在 XCode 5.1 DP 和 iOS 7.1 beta 中看到的,苹果试图解决这个问题。现在,分隔符有时会在最后一行下面显示,在刷新之后,但在创建 tableview 之后不会显示。

49042 次浏览

如果需要,这里有一个更简单(尽管有点乱)的解决方案,尝试在重新加载数据并完成默认动画之后选择和取消选择单元格。

只要加上:

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

我也有分隔符丢失的问题,我发现这个问题只有当 heightForRowAtIndexPath返回一个十进制数时才会发生。解决方案:

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

令人惊讶的是,来回改变细胞的 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;

我们在应用程序中遇到了这个问题。当用户选择一个单元格时,一个新的表视图被推送到导航控制器堆栈上,然后当用户弹出它时,分隔符就不见了。我们通过将 [self.tableView deselectRowAtIndexPath:indexPath animated:NO];放在 didSelectRowAtIndexPath表视图委托方法中来解决这个问题。

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

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

你有没有尝试在表格的页眉和页脚添加一个高度为1的 UIView,背景颜色为浅灰色?基本上它会模仿第一个和最后一个分隔符。

这对我很有效:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


// fix for separators bug in iOS 7
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

我解决这个问题的方法是在 IB 中设置: Molecular ator Inset = custom,left = 0,right = 0

详细解释一下 airpaulg 的答案,因为它并不完全适合我。

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

然后我注意到浅灰色太暗了。我通过抓取当前桌面视图的分隔符颜色并使用:

UIColor * separatorGray = [ self.briefcaseTableView separatorColor ] ; [ footerPartiator setBackground Color: 披上灰色的分隔符] ;

@ 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;
}

对 airpaulg 答案的补充。

所以基本上一个人必须实现两个 UITablegenerate 方法,这是我的解决方案,它可以在 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];

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

看起来这个问题在很多情况下都表现出来了。

对我来说,这与细胞选择有关。我不知道为什么,也没有时间深入研究,但我可以说,当我把细胞的 selectionStyle设为零时,它就开始发生了。即:

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

我尝试使用上面的一些委托方法来切换 tableViewseparatorStyle属性,但他们似乎没有做任何事情来修复我的问题。

我之所以需要它是因为我根本不需要细胞选择。

所以,我确实找到了一些对我有用的东西。我刚刚关闭了 UITableView的选择功能:

tableView.allowsSelection = NO;

如果你不需要细胞选择,希望这个能帮到某人。

要修复上述问题,请在 viewDidLoad 中添加空页脚。

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

请不要在 viewForFooterInSection 委托方法中使用上面的代码行。

我的 UITableView 底部还存在分隔线显示不一致的问题。 通过使用自定义页脚视图,我能够创建一个类似的行,并将其显示在可能存在的行(有时缺少这一行)的顶部。

这个解决方案的唯一问题是,苹果可能有一天会改变生产线的厚度

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

我转储了受影响单元的子视图层次结构,发现 _UITableViewCellSeparatorView被设置为隐藏。难怪没有显示出来!

我在我的 UITableViewCell子类中覆盖了 layoutSubviews,现在分隔符可靠地显示了:

目标-C :

- (void)layoutSubviews {
[super layoutSubviews];


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

斯威夫特 :

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
}
}
}

这里提出的其他解决方案对我来说并不一致,或者看起来很笨拙(添加自定义的1px 页脚视图)。

对我来说,最重要的是重新加载下面的分隔线不会出现的行:

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

我已经决定将这些代码行放在表格视图更新发生的地方:

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;

我用另一种方法来解决这个问题: 添加一个高度为0.5 px,颜色为浅灰色的图层到 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;
}
}
}

正如其他人提到的,这个问题似乎以多种方式表现出来。我通过以下方法解决了我的问题:

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

通过对答案和解决方案的研究,我得出了这样的观察结果:

这在 iOS7和 iOS8中似乎都有问题。我注意到在 viewDidLoad方法中从代码中选择 cell 时出现的问题:

1)如果有人不介意在显示视图和选择单元格之间明显的延迟,那么在 viewDidAppear:中就可以解决这个问题

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

3)增加自己的分隔器似乎是最灵活和最好的现在,但需要更多的编码:)

在进行单元格更新之前,您需要删除一个单元格选区。然后您可以恢复选区。

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

viewWillAppear中设置风格对我很有用。

由于这仍然是 IOS 8的一个问题,我将在 Swift 中添加我的解决方案。将 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()
}

一个简单而干净的解决方案,可以在 iOS8和 iOS9(beta 1)上运行

下面是一个简单的、 干净和非侵入式的解决方案,它涉及调用一个类别方法来修复分隔符。

您所需要做的就是沿着单元格的层次结构向下走,然后取消隐藏分隔符,如下所示:

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

这样,您就可以在导致它们消失的操作之后立即在 tableView 上调用 -fixSeparatos。对我来说,是在调用 [tableView beginUpdates][tableView endUpdates]之后。

正如我在开始时所说的,我已经在 iOS8和 iOS9上测试了这个系统。我认为它甚至可以在 iOS7上运行,但是我没有办法在那里尝试。正如您可能已经意识到的那样,这会干扰计算单元的内部结构,因此它可能会在将来的某个版本中停止工作。苹果理论上可以(0.001% 的几率)因为这个拒绝你的应用,但是我不知道他们怎么可能知道你在做什么(检查类的后缀不能被静态分析器检测到,这是很糟糕的事情,我是这么认为的)。

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

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: Will DisplayCellCellForRowAtIndexPath定制

这是我解决这个问题的方法。插入单元格后,重新加载该节。如果重新加载整个部分对您来说过于密集,那么只需重新加载上面和下面的 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];

唯一的解决办法: 在 tableView 所在的. m 文件的@实现上面写下下面几行代码。

@interface UITableViewCell (fixSeparator)
- (void)layoutSubviews;


@end


@implementation UITableViewCell (fixSeparator)


- (void)layoutSubviews {
[super layoutSubviews];


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


@end

基于@ortwin-gentz 的评论,这个解决方案适合我在 iOS9中使用。

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
}
}


}

(快速代码)

在我的 tableView 的一些方法中调用 EndUpdate ()之后,我使用了 FixCellsPartiator ()函数,例如:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {


//  Perform some stuff
//  ...


self.tableView.endUpdates()
self.fixCellsSeparator()


}

我希望这个解决方案对某些人有帮助!

遇到了类似的问题,我发现了另一个好的解决方案,特别是当你的 dataSource 不大的时候,在你实现 -(void)scrollViewDidScroll:(UIScrollView *)scrollView方法的时候重新加载 tableData,这里有一个例子:

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


else {
[self.tableView2 reloadData];
}
}

您还可以基于可见的 dataSource 重新加载不可见的数据,但这需要更多的修改。

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

希望能有帮助!

对我有效的方法是在启动更新和终止更新之后重新加载数据:

private func animateCellHeighChangeForTableView(tableView: UITableView, withDuration duration: Double) {
UIView.animateWithDuration(duration) { () -> Void in
tableView.beginUpdates();
tableView.endUpdates();
tableView.reloadData();
}
}

当使用动画插入/删除行时,会出现分隔符消失的问题。我解决这个问题的方法是调用 deselectRowAtIndexPath()

var insertion = [NSIndexPath]()
var deletion = [NSIndexPath]()
// TODO: populate the insertion array and deletion array


tableView.beginUpdates()
tableView.deleteRowsAtIndexPaths(deletion, withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths(insertion, withRowAnimation: .Fade)
if let indexPath = tableView.indexPathForSelectedRow {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
tableView.endUpdates()

一个简单、干净、高效的方法是使用 good ole KVC:

UIView *separatorView = [self valueForKey:@"separatorView"]; // pull separator using KVC


if (separatorView) {
separatorView.hidden = NO;
}

把它放在你的细胞类的 layoutSubviews中,这样就可以解决你的问题了。

可以修改@Lee 的答案,以获得默认的表视图分隔符样式,而不显示最后一行的分隔符,这很奇怪。希望能帮到别人。

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {


if indexPath.row >= yourDataSource.count - 1{
return
}


let lineView = UIView(frame: CGRectMake(20, cell.contentView.frame.size.height - 1.0, cell.contentView.frame.size.width, 0.5))
lineView.backgroundColor = tableView.separatorColor
cell.contentView.addSubview(lineView)
}

在我的案例中,我尝试了所有列出的答案,但不适合我,我使用两个答案,这适合我。以下是解决方案:

在 UITableViewConController 中添加以下代码行

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


// fix for separators bug in iOS 7
self.tableView.separatorStyle = .none;
self.tableView.separatorStyle = .singleLine;
}

现在,在 UITableViewCell 中重写下面的方法

    override func layoutSubviews() {
super.layoutSubviews()


guard let superview = contentView.superview else {
return
}
for subview in superview.subviews {
if String(describing: type(of: subview)).hasSuffix("SeparatorView") {
subview.isHidden = false
}
}
}

我希望这对其他人也有用。谢谢