为什么UITableViewCell仍然突出显示?


145

是什么导致表格视图单元格在被触​​摸后仍保持突出显示状态?我单击该单元格,并可以看到它在按详细视图时保持突出显示。弹出细节视图后,单元格仍将突出显示。

Answers:


262

在你didSelectRowAtIndexPath需要调用deselectRowAtIndexPath取消选择的单元格。

因此,无论您在做什么,didSelectRowAtIndexPath也都需要调用它deselectRowAtIndexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

11
deselectRowAtIndexPath如果选择该行将弹出一个新视图,则我更喜欢在viewDidAppear中调用。
notnoop

5
实际上,这不是正确的调用位置,确实...尝试使用带有表的Apple应用程序(“联系人”是一个很好的应用程序),当您推送到新屏幕后,您会看到,返回时该单元格仍突出显示在取消选择之前短暂地进行。从理论上讲,我认为您不必立即进行取消选择就无需做任何额外的工作,因此不需要viewDidAppear中的代码...
Kendall Helmstetter Gelner 2009年

6
@ Kendall,@ 4thSpace:也许我最后的评论对于我指的是谁感到困惑,对此表示歉意。UITableViewController -deselectRowAtIndexPath:animated:从中对其tableView属性调用方法-viewDidAppear。但是,如果你在一个UIViewController子类有一个表视图,你应该叫-deselectRowAtIndexPath:animated:-viewDidAppear自己。:)
Daniel Tull

5
在我的UITableViewController子类中,它实际上是对它的覆盖-viewWillAppear:。添加呼叫以[super viewWillAppear:animated]使其重新工作。
Ben Challenor

5
从3.2开始,如果您UITableViewControllerclearsSelectionOnViewWillAppear属性设置为YES(默认值),并且没有阻止您[super viewWillAppear]进行调用,则会发生自动取消选择行为。
2011年

62

最干净的方法是在viewWillAppear上:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Unselect the selected row if any
    NSIndexPath*    selection = [self.tableView indexPathForSelectedRow];
    if (selection) {
        [self.tableView deselectRowAtIndexPath:selection animated:YES];
    }
}

这样,当您返回到控制器时,您将获得淡入选择的动画效果。

取自http://forums.macrumors.com/showthread.php?t=577677

迅捷版

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // deselect the selected row if any
    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRowNotNill = selectedRow {
        tableView.deselectRow(at: selectedRowNotNill, animated: true)
    }
}

1
我希望这是大多数人不使用UITableViewController时想要的。+1
MikeB

3
我不知道人们现在在做什么,因为iOS 7允许用户“拖动”回来。部分拖动但未完成操作将触发viewWillAppear。当用户返回真实状态时,将不会选择该行。
本·帕克

1
@BenPackard只是调用它viewDidAppear
squarefrog 2014年

@Jessica indexPathForSelectedRow调用可以返回nil,因此应进行检查。文档状态标识选定行的行索引和节索引的索引路径;如果索引路径无效,则为nil。
Gordonium 2015年

这应该标记为已接受的答案,它对UI更加友好,因此用户可以在返回后进行选择,这是完美的
Yahya Alshaar

20

你继承了阶级-(void)viewWillAppear:(BOOL)animated吗?当您不使用[super viewWillAppear:animated];自定义方法调用时,选定的UITableViewCell不会取消选择。


19

对于Swift用户,请将其添加到您的代码中:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

除了在Swift中而不是在Obj-C中之外,这都是paulthenerd的答案。


1
它不是被自身取消选择,我的意思是您放手的那一刻?
亲爱的2016年

@Honey可能是在以前的iOS版本中,或者在视图消失时出现的,但肯定不会在iOS 10(可能更早)及更高版本中出现。
杰米·伯奇

9

Swift 3解决方案

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

7

如果您使用的是UITableViewCell,请注释以下行

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{

 // [super setSelected:selected animated:animated];

}

希望这可以帮助。


4

使用Swift 4更新

经过几次实验,也基于先前的答案,我得出的结论是,可以通过两种方式实现最佳行为:(实际上几乎是相同的)

// First Solution: delegate of the table View
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: false)
}

// Second Solution: With the life cycle of the view.
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        tableView.deselectRow(at: selectedRow, animated: false)
    }
}

我个人采用第一个解决方案,因为它更简洁。如果返回tableView时需要一些动画,另一种可能性是使用viewWillAppear

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let selectedRow: IndexPath? = _view.tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        _view.tableView.deselectRow(at: selectedRow, animated: true)
    }
}

最后但并非最不重要的一点是,如果您使用的是UITableViewController,还可以利用clearsSelectionOnViewWillAppear属性。


3

要获得Kendall Helmstetter Gelner在其注释中描述的行为,您可能不希望deselectRowAtIndexPath,而是希望控制器上具有clearsSelectionOnViewWillAppear属性。也许是偶然将其设置为“是”?

请参阅默认Apple模板中的注释,以获取新的UITableViewController子类:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}

2

我的向下钻取应用程序也遇到了这个问题。在按下另一个ViewController之后,我将称为VC的viewcontroller返回后,VC中的选定单元格仍然突出显示。在我的应用程序中,我创建了VC以处理向下钻取的第二个级别(三个级别中的第二个级别)。

在我的情况下,问题是VC是UIViewController(包含一个包含TableView的View)。我改用VC作为UITableViewController(包含一个TableView)。从推送返回后,UITableViewController类自动处理表单元格的反突出显示。帖子“ tableView中的deselectRowAtIndexPath问题 ”的第二个答案给出了此问题的更完整答案。

根视图控制器不会发生此问题,因为当我在XCode中将应用程序创建为“基于导航的应用程序”时,生成的根视图控制器已被子类化为UITableViewController。


1

如果这些都不适合您,请考虑以下解决方法:

使用放松搜索来呼叫:

@IBAction func unwind_ToTableVC (segue: UIStoryboardSegue) {
    if let index = tableView.indexPathForSelectedRow {
        tableView.deselectRowAtIndexPath(index, animated: true)
    }
}

为什么这样 主要是如果您无法在正确的时间运行取消选择代码。我在无法在viewWillAppear上运行时遇到了麻烦,因此展开效果要好得多。

脚步:

  1. 将展开的序列(或从上方粘贴)写入您的第一个VC(带表的一个)

  2. 转到第二个VC。按住Control并从您用来取消该VC的“取消/完成/其他”按钮中拖动,然后拖动到顶部的“退出”图标。

  3. 选择您在步骤1中创建的放松序列

    祝好运。


这是在viewDidAppear无法启动时的最佳解决方案(即,如果子视图以表单形式显示,并且不能覆盖整个屏幕)。
pheedsta

1

我正在使用CoreData,因此对我有用的代码是Swift中来自各种答案的想法的组合:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}

1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

0

我长期以来一直遇到相同的问题,以防万一其他人正在挣扎:

看看你的 -tableView: cellForRowAtIndexPath:,看看您是要创建单元格还是使用“重用标识符”。如果是后者,请确保IB中的表具有带有该标识符的单元格。如果您不使用重用标识符,则只需为每行创建一个新单元格。

然后,这将使您的表出现预期的“淡入淡出选定的行”。


0

在UITableViewCell类中使用此方法

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

   // Just comment This line of code
   // [super setSelected:selected animated:animated];        
}

0

对于Swift 3:我希望它可以在viewDidDisappear中使用

定义:

    var selectedIndexPath = IndexPath()

在viewDidDisappear中:

    override func viewDidDisappear(_ animated: Bool) {
    yourTableView.deselectRow(at: selectedIndexPath, animated: true)
}

在didSelectRowAtIndexPath中:-

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}

0

如果单元格在触摸后仍保持突出显示,则可以调用UITabelView方法,

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

`[tableView deselectRowAtIndexPath:indexPath animated:YES];`   

}

或者,您可以使用以下方法并根据需要对其进行修改,

//标记:UITableViewDelegate

func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.greenColor()
  }
}

func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.blackColor()
  }
} 

0

Xcode 10,Swift 4

我遇到了同样的问题,发现我在tableViewController的底部留下了一个空的viewWillAppear调用。一旦删除了空的覆盖功能,该行就不再在返回tableView视图时保持突出显示状态。

问题功能

override func viewWillAppear(_ animated: Bool) {
  // need to remove this function if not being used.
}

删除空函数解决了我的问题。


0

Swift 5解决方案:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.