如何取消选择UITableView中已选中的单元格?

233

我正在开发一个项目,在该项目中我需要预先选择特定的单元格。

使用-willDisplayCell,我可以预先选择单元格,但是当用户点击其他任何单元格时,我无法取消选择。

- (void)tableView:(UITableView*)tableView 
        willDisplayCell:(UITableViewCell*)cell
        forRowAtIndexPath:(NSIndexPath*)indexPath
{ 
    AppDelegate_iPad *appDelegte = 
      (AppDelegate_iPad *)[[UIApplication sharedApplication] delegate];

    if ([appDelegte.indexPathDelegate row] == [indexPath row])
    {
        [cell setSelected:YES];    
    } 
}

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

    AppDelegate_iPad *appDelegte = 
      (AppDelegate_iPad *)[[UIApplication sharedApplication] delegate];

    NSIndexPath *indexpath1 = appDelegte.indexPathDelegate;
    appDelegte.indexPathDelegate = indexPath;
    [materialTable deselectRowAtIndexPath:indexpath1 animated:NO];
}

你能帮忙吗?


11
这个问题需要有一个被接受的答案。 - Titouan de Bailleul
23个回答

435

使用这段代码。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
 {
    //Change the selected background view of the cell.
     [tableView deselectRowAtIndexPath:indexPath animated:YES];
 }

Swift 3.0:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    //Change the selected background view of the cell.
    tableView.deselectRow(at: indexPath, animated: true)
}

1
有一个didDeselectRowAtIndexPath可以用来取消选择先前的行。 - huggie
3
我喜欢认为我不能给这篇帖子点赞,因为这会导致整数溢出 :) - Milo
1
嗨@ram,您需要在此问题上选择一个答案。 - Fattie
4
我不理解...这段代码永远不会让任何东西被选择。 - C. Tewalt
@matrixugly是正确的。在willSelectRowAt:中执行这个操作更为合适。在这里可以查看一个更完整的答案:https://dev59.com/p2cs5IYBdhLWcg3woVd- - HuaTham

119

在表视图的代理方法didSelectRowAtIndexpath中(或任何地方)使用以下方法:

[myTable deselectRowAtIndexPath:[myTable indexPathForSelectedRow] animated:YES];

2
值得注意的是,indexPathForSelectedRow 是一个方法而不是属性。 - FreeAsInBeer
太好了!我不知道[myTable indexPathForSelectedRow]。之前我一直在循环遍历单元格。谢谢! - abc123
@FreeAsInBeer 这种区别有什么重要的意义吗?属性访问器实质上是方法。 - devios1
@chaiguy 如果你不介意你的同事认为你是邪恶的,那就没问题。 - FreeAsInBeer
@FreeAsInBeer 但即使它是一个方法调用,它所做的只是检索一个值 - 不会影响性能,对吗?即使在最慢的设备上也是如此。 - Supertecnoboff
1
@Supertecnoboff 两种变体之间的性能没有区别。 - FreeAsInBeer

44

为此,使用Swift创建一个扩展可能是有用的。

Swift 4和Swift 5:

Swift扩展(例如在UITableViewExtension.swift文件中):

import UIKit

extension UITableView {

    func deselectSelectedRow(animated: Bool)
    {
        if let indexPathForSelectedRow = self.indexPathForSelectedRow {
            self.deselectRow(at: indexPathForSelectedRow, animated: animated)
        }
    }

}

例如:

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

    self.tableView.deselectSelectedRow(animated: true)
}

3
在我看来,这个答案更好,因为将“desolation”放在“viewWillAppear()”方法中有助于用户理解他从哪里返回。 - MonsieurDart
我需要的完美的。 - Patel Jigar

40

试试这个:

for (NSIndexPath *indexPath in tableView.indexPathsForSelectedRows) {
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
}

1
干得好...我认为第二行的'index'应该改成indexPath。 - El Tomato
在iOS 11 Swift 4上不支持此功能。 - Boris Nikolic

28

请通过委托方法检查它是否正确。例如:

-(void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath

对于

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

一直在调用错误的方法,啊!谢谢! - Damir Kotoric
1
哦,天啊...该死的自动补全!我花了好几个小时才摆脱它!哎呀...我想吻你! - George Asda

26

Swift 4:

tableView.deselectRow(at: indexPath, animated: true)

不需要声明为非可选项,但这是正确的。 - Michael

23

这是Swift 4的解决方案

 in tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
只需添加。
tableView.deselectRow(at: indexPath, animated: true)

它的效果非常好

例子:

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

在您的TableView上添加编辑选择之前,将无法选择任何单元格,因为当您完成选择时,它将取消选择它 :) - Mehdi Chennoufi
当您不编辑时,这绝对是正确的方法,当您“点击行以执行某些操作”时。 - Fattie

11
此外,除了设置单元格为选定状态之外,您还需要通知tableView该单元格已被选定。在您的willDisplayCell:方法中添加一个调用-tableView:selectRowAtIndexPath:animated:scrollPosition:,然后您可以像正常情况下取消选择它。
- (void)tableView:(UITableView*)tableView 
  willDisplayCell:(UITableViewCell*)cell
forRowAtIndexPath:(NSIndexPath*)indexPath
{ 
    AppDelegate_iPad *appDelegte = (AppDelegate_iPad *)[[UIApplication sharedApplication] delegate];

    if ([appDelegte.indexPathDelegate row] == [indexPath row])
    {
        // SELECT CELL
        [cell setSelected:YES]; 
        // TELL TABLEVIEW THAT ROW IS SELECTED
        [tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];   
    } 
}

确保使用UITableViewScrollPositionNone以避免奇怪的滚动行为。


1
完全正确。我认为 [cell setSelected:YES] 可以省略:selectRowAtIndexPath 会处理单元格的 selected 状态。 - spassas
这个答案适用于具有多选功能的UITableView。点赞。 - Danny Bravo

7

Swift 4:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    let cell = tableView.cellForRow(at: indexPath)
    if cell?.isSelected == true { // check if cell has been previously selected
        tableView.deselectRow(at: indexPath, animated: true)
        return nil
    } else {
        return indexPath
    }
}

2
这对我在Swift 3中起作用。只需要在tableView.deselectRow...之后添加self.tableView(tableView, didDeselectRowAt: indexPath),因为它不会自动调用。 - elysch

7

基于saikirans的解决方案,我写了下面这段代码,对我很有帮助。在.m文件中:

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

    if(selectedRowIndex && indexPath.row == selectedRowIndex.row) {

        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        selectedRowIndex = nil;

    }

    else {  self.selectedRowIndex = [indexPath retain];   }

    [tableView beginUpdates];
    [tableView endUpdates];

}

在头文件中:

@property (retain, nonatomic) NSIndexPath* selectedRowIndex;

我也没有太多经验,所以请再检查内存泄漏等问题。


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