UITableViewCell分隔符在iOS7中消失

时间:2013-09-20 19:38:46

标签: ios objective-c uitableview cocoa-touch uikit

我只在iOS 7中遇到UITableView的奇怪问题。

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

在我的情况下,tableViewStoryboard加载UITableViewStylePlain样式。问题肯定不在UITableViewCellSeparatorStyle中,而是从默认UITableViewCellSeparatorStyleSingleLine更改。

当我在 Apple Dev论坛 herehere )阅读时,其他人也会遇到此类问题找到了一些解决方法,例如:

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

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

有什么想法吗?

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

37 个答案:

答案 0 :(得分:77)

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

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

<强>目标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
        }
    }
}

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

答案 1 :(得分:42)

这对我有用:

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

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

答案 2 :(得分:12)

我也遇到了丢失分隔符的问题,我发现问题只发生在 heightForRowAtIndexPath 返回小数时。解决方案:

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

答案 3 :(得分:11)

您是否尝试在表格的页眉和页脚中添加高度为1的UIView,并带有浅灰色背景色?基本上它会模拟第一个和最后一个分隔符。

答案 4 :(得分:8)

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

答案 5 :(得分:7)

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

答案 6 :(得分:6)

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

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

答案 7 :(得分:6)

如果你需要一个更容易(虽然有点乱)解决方法,尝试在重新加载数据并完成默认动画后选择和取消选择单元格。

只需添加:

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

答案 8 :(得分:4)

基于@ ortwin-gentz的评论,此解决方案适用于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()

}

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

答案 9 :(得分:4)

一个简单而干净的解决方案,适用于iOS 8和iOS 9(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]之后。

正如我在开始时所说,我已经在iOS 8和iOS 9上对此进行了测试。我认为它甚至可以在iOS 7上运行,但我没有办法在那里尝试。正如您可能已经意识到的那样,这确实会影响单元的内部,因此它可能会在将来的某个版本中停止工作。理论上Apple可以(0.001%的几率)拒绝你的应用程序因为这个,但是我无法看到他们怎么能找到你在那里做的事情(检查一个类的后缀是不是可以被检测到静态分析仪不好,IMO)。

答案 10 :(得分:2)

我尝试了很多建议但无法修复。最后我决定自定义分隔线,如下所示:

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

答案 11 :(得分:2)

补充airpaulg的答案。

所以基本上必须实现两个UITableDelegate方法。这是我的解决方案,适用于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;
    }
}

答案 12 :(得分:2)

这解决了我的问题:

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

答案 13 :(得分:2)

似乎这个问题在很多情况下都会出现。

对我而言,它与细胞选择有关。我不知道为什么,也没有时间深入挖掘它,但我可以说当我将单元格selectionStyle设置为无时,它就开始发生了。即:

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

我尝试使用上面的一些委托方法来切换separatorStyle tableView UITableView属性,但他们似乎无法解决我的问题。

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

所以,我找到了适合我的东西。我刚刚在tableView.allowsSelection = NO; 上禁用了选择:

{{1}}

希望这可以帮助某人,如果你不需要选择细胞。

答案 14 :(得分: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;

答案 15 :(得分:1)

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

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

答案 16 :(得分:1)

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

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

请不要在viewForFooterInSection委托方法中使用上述行。意味着不要实现viewForFooterInSection方法。

答案 17 :(得分:1)

相当令人惊讶的是,来回更改单元格的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;

答案 18 :(得分:1)

我还遇到了UITableView底部不一致的分隔线显示问题。 使用自定义页脚视图,我已经能够创建一个类似的行并将其显示在潜在的现有页面之上(有时会丢失)。

此解决方案的唯一问题是Apple可能会在某一天更改线条的粗细

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

答案 19 :(得分:0)

扩大airpaulg答案,因为它对我来说并不完全有用..

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

然后我注意到浅灰色太暗了。我通过抓取tableview的当前分隔符颜色并使用它来修复此问题:

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

答案 20 :(得分:0)

在我的情况下,我尝试了所有列出的答案,但没有为我工作,我使用了两个答案,这对我有用。以下是解决方案:

在UITableViewConstroller中添加以下行

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

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

答案 21 :(得分:0)

修改@ 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)
    }

答案 22 :(得分:0)

一个简单,干净,高效的方法这样做,而不必循环遍历每个细胞出列/创建时调用的细胞的每个子视图,使用良好的kVC :

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

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

坚持你的细胞类layoutSubviews,这应该可以解决你的问题。

答案 23 :(得分:0)

当我插入/删除带动画的行时,会出现消失的分隔符问题。为我解决的是调用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()

答案 24 :(得分:0)

对我来说有用的是在beginUpdates和endUpdates之后重新加载数据:

shlex

答案 25 :(得分:0)

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

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

      else {
          [self.tableView2 reloadData];
      }
}

您还可以根据可见的dataSource重新加载不可见的数据,但这需要更多的黑客攻击。

请记住,此委托功能属于UITableViewDelegate协议!

希望它有所帮助!

答案 26 :(得分:0)

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

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

答案 27 :(得分:0)

由于这仍然是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()
    }

答案 28 :(得分:0)

viewWillAppear中设置样式对我有用。

答案 29 :(得分:0)

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

答案 30 :(得分:0)

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

这在iOS 7和8中似乎都有问题。我在viewDidLoad方法中从代码中选择单元格时发现了问题所以:

1)如果有人不介意在展示视图和选择单元格之间有明显的延迟,那么viewDidAppear:中的解决方法是这样做的

2)the second solution为我工作,但代码看起来有点脆弱,因为它基于UITableViewCell的内部实现

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

答案 31 :(得分:0)

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

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

答案 32 :(得分:0)

在你的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;
        }
    }
}

答案 33 :(得分:0)

我以另一种方式解决了这个问题:将一个高度为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;

答案 34 :(得分:0)

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

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

答案 35 :(得分:-1)

唯一的解决办法:在下面的代码行中写下.View文件所在的@implementation。

@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

答案 36 :(得分:-3)

我通过在IB中设置解决了这个问题:分隔符插入=自定义,左边= 0,右边= 0