129

UITableView只在 iOS 7 中遇到了一些奇怪的问题。

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

在我的情况下是从with样式tableView加载的。问题肯定不在,从默认没有改变。StoryboardUITableViewStylePlainUITableViewCellSeparatorStyleUITableViewCellSeparatorStyleSingleLine

正如我在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 中看到的,Apple 试图解决这个问题。现在分隔符有时会根据需要显示在最后一行下方,经过一些刷新,但不是在创建 tableview 之后。

4

37 回答 37

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 页脚视图)。

于 2014-05-06T15:14:53.963 回答
42

这对我有用:

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

    // fix for separators bug in iOS 7
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
于 2013-11-21T01:23:32.723 回答
12

我也遇到了缺少分隔符的问题,我发现问题仅在heightForRowAtIndexPath返回十进制数时出现。解决方案:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return ceil(yourHeight) // Ceiling this value fixes disappearing separators
}
于 2013-10-01T15:26:31.217 回答
11

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

于 2013-10-28T21:22:56.277 回答
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;
}
于 2013-12-06T12:14:57.967 回答
7

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

于 2013-10-17T01:13:37.823 回答
6

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

只需添加:

[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
于 2013-09-29T16:46:40.970 回答
6

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

if (indexPath.row > 0) {
    NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section];
    [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationNone];
}
于 2013-10-21T23:12:37.507 回答
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

有了这个,您可以-fixSeparatos在导致它们消失的操作之后立即调用您的 tableView。就我而言,是在调用[tableView beginUpdates]and之后[tableView endUpdates]

正如我在开头所说的,我已经在 iOS 8 和 iOS 9 上测试过。我认为它甚至可以在 iOS 7 上工作,但我没有办法在那里尝试。正如您可能知道的那样,这确实会影响单元的内部结构,因此它可能会在将来的某个版本中停止工作。苹果理论上可以(0.001% 的机会)因此拒绝你的应用程序,但我看不出他们怎么能发现你在那里做什么(检查类的后缀不能被静态分析器检测为某事糟糕,国际海事组织)。

于 2015-06-18T13:18:28.777 回答
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()

}

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

于 2016-03-26T15:55:25.867 回答
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;
    }
}
于 2014-01-09T17:26:30.810 回答
2

这为我解决了这个问题:

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

于 2014-01-21T10:02:58.107 回答
2

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

对我来说,这与细胞选择有关。我不知道为什么,也没有时间深入研究它,但我可以说当我将单元格设置selectionStyle为无时它开始发生。IE:

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

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

我需要它的全部原因是因为我什至不需要单元格选择。

所以,我确实找到了对我有用的东西。我刚刚禁用了选择UITableView

tableView.allowsSelection = NO;

如果您不需要单元格选择,希望这对某人有所帮助。

于 2014-03-26T22:11:17.107 回答
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不是cellForRowAtIndexPath

于 2015-08-18T06:31:11.407 回答
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;
于 2013-10-16T10:52:43.850 回答
1

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

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

请不要在 viewForFooterInSection 委托方法中使用上述行。表示不要实现 viewForFooterInSection 方法。

于 2014-03-27T15:02:16.953 回答
1

我的 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;
}
于 2014-04-06T19:42:17.443 回答
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;
于 2014-07-09T16:32:23.063 回答
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];
于 2015-04-12T11:12:02.627 回答
0

扩展airpaulg的答案,因为它并不完全适合我..

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

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

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

于 2013-11-26T17:39:37.863 回答
0

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

于 2014-02-22T11:37:43.857 回答
0

对我来说不同的是重新加载底部分隔线不会出现的行:

NSIndexPath *indexPath = 
     [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];  
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
于 2014-07-02T15:00:21.870 回答
0

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

代码是这样的:

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;
于 2014-07-22T03:25:17.770 回答
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;
        }
    }
}
于 2014-09-09T13:03:25.277 回答
0

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

[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
于 2014-10-07T18:16:12.480 回答
0

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

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

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

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

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

于 2014-11-27T08:43:15.163 回答
0

设置风格viewWillAppear对我有用。

于 2015-04-21T09:51:26.923 回答
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()
    }
于 2015-04-29T11:31:09.650 回答
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];
于 2015-09-11T17:36:22.907 回答
0

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

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

      else {
          [self.tableView2 reloadData];
      }
}

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

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

希望能帮助到你!

于 2016-05-05T16:36:15.067 回答
0

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

private func animateCellHeighChangeForTableView(tableView: UITableView, withDuration duration: Double) {
     UIView.animateWithDuration(duration) { () -> Void in
        tableView.beginUpdates();
        tableView.endUpdates();
        tableView.reloadData();
     }
}
于 2016-06-04T03:54:24.420 回答
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()
于 2016-07-15T21:09:23.427 回答
0

一种简单、干净、有效的方法是使用良好的 ole KVC,而无需遍历单元格的每个子视图(每次出列/创建单元格时都会调用该子视图):

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

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

把它放在layoutSubviews你的单元格中,这应该可以解决你的问题。

于 2016-10-18T22:32:51.390 回答
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)
    }
于 2016-11-01T12:40:56.870 回答
0

就我而言,我尝试了所有列出的答案,但对我不起作用,我使用了两个对我有用的答案。以下是解决方案:

在你的 UITableViewController 中添加以下行

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

我希望这也适用于其他人。谢谢

于 2017-08-26T06:43:22.577 回答
-1

一个也是唯一的解决方法:在 tableView 所在的 .m 文件的@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
于 2015-11-26T14:39:03.760 回答
-3

我通过在 IB 中设置解决了这个问题:Separator Inset = custom, left = 0, right = 0

于 2013-11-22T07:07:19.803 回答