iOS7中选中单元格时UITableView的分隔线消失

54

在我的tableView中,我在单元格之间设置了分隔线。我允许选择多个单元格。以下是我设置选定单元格背景颜色的代码:

UIView *cellBackgroundColorView = [[UIView alloc] initWithFrame:cell.frame];
[cellBackgroundColorView setBackgroundColor:[UIColor darkGray]];
[cell setSelectedBackgroundView:cellBackgroundColorView];

问题在于,如果选择了相邻的两个单元格,在iOS7中它们之间没有分隔线,而在iOS6中有(正如预期的那样)。

我甚至尝试将cellBackgroundColorView的框架高度设置为cell.frame - 1.0,但这也不起作用。

有什么想法吗?

24个回答

38

我还没有彻底弄清楚它的原因(乍一看似乎是iOS 7的一个错误..),但我已经找到了一个解决方法。在tableView:didSelectRowAtIndexPath中,如果您发送以下两条消息,问题将得到视觉上的解决(但可能会牺牲一些性能)。

[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

为了使这个代码对我生效,deselectRowAtIndexPath:animated: 方法中的 animated 参数必须设置为 YES。reloadRowsAtIndexPaths:withRowAnimation: 方法使用的动画效果并不重要。


我一直在寻找这个确切的问题,但是这对我没有用,单元格只是取消选择,并且不保留我为所选视图设置的背景颜色。我是否遗漏了什么? - skinsfan00atg
我的回答仅涉及单元格被点击后分隔线消失的问题。我假设问题中的背景颜色部分只是支持信息。如果您在处理背景颜色方面遇到麻烦,下面的其中一种解决方法可能更适合。 - Mark
你在didSelectRowAtIndexPath中调用了deselectRowAtIndexPath,那不会自动取消你选择的任何行吗?我有什么遗漏吗? - HaloZero
2
@Mark,如果我尝试使用你的代码,结果是我选择的单元格最终变成了未选择状态,这与初衷相悖。我想要同时选择(高亮背景)多个(相邻的)单元格,并且显示分隔符。 - artooras
就我所理解的@Lion的意思,如果我在reload时使用animation:UITableViewRowAnimationNone,这对我来说是有效的;如果我使用“automatic”,分隔符会消失并带走单元格内容。 - Geoffrey Wiseman
显示剩余2条评论

29

将此代码添加到行的单元格,位于indexpath

cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.backgroundColor = [UIColor clearColor];

这对我来说是解决方法。 - Nerrolken
这是正确的答案。@Mark的答案完全错误。它取消了应该保持选中的内容,这毫无意义。 - Earl Grey
14
我感到困惑!cell.selectionStyle = UITableViewCellSelectionStyleNone; 会导致无法选择单元格!这如何解决手头的问题? - M. Porooshani
谢谢!对我有用。 - Kishore
需要注意的是,将selectionStyle = UITableViewCellSelectionStyleNone设置为UITableViewCellSelectionStyleNone会阻止UITableViewController.clearsSelectionOnViewWillAppear = YES按预期工作。当在导航控制器中弹出时,VC将不会在viewWillAppear中呈现单元格的取消选择动画。 - Brody Robertson

16

在我的情况下,我正在对一行进行动画处理,所以我只需要像这样输入:

在我的情况下,我正在对一行进行动画处理,所以我只需要输入类似以下的内容:

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

[tableView beginUpdates];
[tableView deselectRowAtIndexPath:indexPath animated:NO]; 
//if you are doing any animation you have deselect the row here inside. 
[tableView endUpdates];
} 

1
这个方法在iOS 9中仍然有效,但是当我对一个单元格的高度进行动画处理时,我的tableview中的一行消失了。我通过在didSelectRowAtIndexPath中调用此方法并将其放入我的动画块中来解决了这个问题。 - DogCoffee
如果我省略 begin- 和 endUpdates,它也会在iOS9上工作。然而,在两种情况下,我都失去了取消选择的动画......有任何想法吗? - blackjacx
虽然这个方法可以工作,但是你必须小心使用beginUpdates/endUpdates块,确保在数据源中没有任何变化,否则会导致运行时异常。 - Marc Etcheverry

12

@samvermette的答案解决了我的问题,但我必须先取消选择已选中的行。

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

    //Deselect Row
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];

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

2
如果您的表格启用了多选选项(即当您需要使用复选框附件视图时),则其行为与您的解决方案发生冲突。问题在于选择时调用了deselectRowAtIndexPath:animated:方法。是否有其他方法? - wildmonkey
我自己永远都无法达到那个程度。太棒了,解决方案。 - brduca

7
将其粘贴到您的UITableViewCell类中。
override func layoutSubviews() {
    super.layoutSubviews()

    subviews.forEach { (view) in
        if type(of: view).description() == "_UITableViewCellSeparatorView" {
            view.alpha = 1.0
        }
    }
}

7
当我以编程方式将单元格的选择样式设置为"none"时,再以编程方式选择表格单元格时,我遇到了这个问题。
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: UITableViewCell!
    if tableView == self.jobLevelTableView {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as! CheckboxCell

        // for testing purposes
        let checked = true

        // I used M13Checkbox here, in case anybody was wondering
        cell.checkbox.setCheckState(checked ? .checked : .unchecked, animated: false) 

        if checked {
            tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
        }

        // CULPRIT
        cell.selectionStyle = .none
        return cell
    }

    cell = UITableViewCell()
    return cell
}

当我在Storyboard上设置选择样式(并移除代码等效部分)时,问题解决了! Storyboard is useful

4

在iOS 8上,这个简单的调用就可以做到。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // ....
    [tableView deselectRowAtIndexPath:indexPath animated:YES]

    // ....
}

适用于我。单元格的选择样式为无,表格为单选。 - Dren
只要我在 beginUpdates / endUpdates 块中调用它(或之前),这对我起作用(选择样式为 none,单选)。 - Geoffrey Wiseman

4
这似乎仍然是iOS 7.0.3的问题,但我通过使用一个简单的方法来模拟分隔符来解决它。
首先将UITableView的分隔样式设置为UITableViewCellSeparatorStyleNone。然后,您可以使用自定义的UITableViewCell子类来模拟选中和未选中状态下单元格之间的分隔符:
@implementation MyTableViewCellSubclass

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        CGRect frame = self.bounds;
        frame.origin.y = frame.size.height - 1.f;
        frame.size.height = 1.f;

        // Selected background view
        //
        UIView * separatorView = [[UIView alloc] initWithFrame:frame];
        separatorView.backgroundColor = [UIColor darkGrayColor];
        separatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin;

        UIView * selectedView = [[UIView alloc] initWithFrame:self.bounds];
        selectedView.backgroundColor = [UIColor lightGrayColor];
        [selectedView addSubview:separatorView];

        self.selectedBackgroundView = selectedView;

        // Add separator view to content view for unselected state
        //
        UIView * separatorView2 = [[UIView alloc] initWithFrame:frame];
        separatorView2.backgroundColor = [UIColor darkGrayColor];
        separatorView2.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin;

        [self.contentView addSubview:separatorView2];


    }
    return self;
}


@end

这对我的目的非常有效。谢谢,亲切的先生。 - Stepan Hruda
单元格上方的线仍然缺失。separatorView2 也没有覆盖 accessorView 的区域。 - testing

3

如果您允许iOS应用其自己的默认选中单元格样式,那么这种情况就会发生。目前我找到的最佳解决方法是覆盖选中属性的实现:

在您的单元格子类实现中:

    @synthesize selected = _selected;

在初始化方法中:

    // problem actually is caused when you set following 
    // to UITableViewCellSelectionStyleDefault, so:

    [self setSelectionStyle:UITableViewCellSelectionStyleNone]; 

覆盖方法:

    - (BOOL)selected 
    {
        return _selected;
    }
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated 
    {
        _selected = selected
        if (selected) {

            // apply your own selected style

        }
        else {

            // apply your own deselected style

        }
    }

太棒了!在iOS 9中完美运行。当您仅更改单元格背景颜色而不是添加选定视图时,它还保持分隔线的顶部和底部。太棒了! - David H
其实我有一个需要使用的透明颜色,所以我添加了一个backgroundView,然后对其backgroundColor进行了动画处理。分隔线仍然可见!!! - David H

2

- cellForRowAtIndexPath

Create two separator views (sv1, sv2)

[cell addsubview:sv1];
[cell.selectedBackgroundView addsubview:sv2];

- didSelectRowAtIndexPath

[tableView deselectRowAtIndexPath:indexPath animated:NO];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接