简体   繁体   English

UITableView 点击取消选择单元格

[英]UITableView tap to deselect cell

I have a UITableViewCell that is selected when tapped.我有一个UITableViewCell在点击时被选中。 During this selected state, if the user taps the cell again, I want the cell to deselect.在此选定状态期间,如果用户再次点击该单元格,我希望该单元格取消选择。

I can't find any of the delegate calls being hit.我找不到任何被击中的委托调用。 Any ideas how to implement this?任何想法如何实现这一点? Is it really going to be a gesture recognizer?它真的会成为一个手势识别器吗?

You can actually do this using the delegate method willSelectRowAtIndexPath:你实际上可以使用委托方法willSelectRowAtIndexPath:来做到这willSelectRowAtIndexPath:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if ([cell isSelected]) {
        // Deselect manually.
        [tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath];
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        [tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath];

        return nil;
    }

    return indexPath;
}

Note that deselectRowAtIndexPath: won't call the delegate methods automatically, so you need to make those calls manually.请注意, deselectRowAtIndexPath:不会自动调用委托方法,因此您需要手动进行这些调用。

in Swift 4:在 Swift 4 中:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if let indexPathForSelectedRow = tableView.indexPathForSelectedRow,
        indexPathForSelectedRow == indexPath {
        tableView.deselectRow(at: indexPath, animated: false)
        return nil
    }
    return indexPath
}

When using "Multiple Selection" mode, "didSelectRowAtIndexPath" will not be called when you click a row that is already selected.使用“多选”模式时,单击已选择的行时不会调用“didSelectRowAtIndexPath”。 More than one row can still be selected programatically in "Single Selection" mode and the rows will trigger didSelectRowAtIndexPath on all clicks.在“单选”模式下仍然可以通过编程方式选择多行,并且这些行将在所有点击时触发 didSelectRowAtIndexPath。

Just a heads up to anyone who was having the same problems.只是提醒任何遇到相同问题的人。

Here is an even cleaner solution:这是一个更干净的解决方案:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([[tableView indexPathForSelectedRow] isEqual:indexPath]) {
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        return nil;
    }
    return indexPath;
}

Leave the single selection mode on, but override the following funcs like this:保持单一选择模式,但像这样覆盖以下功能:

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    if tableView.indexPathsForSelectedRows?.contains(indexPath) ?? false {
       tableView.deselectRow(at: indexPath, animated: true)
       return nil
    }

    return indexPath
}

override func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
    return nil
}

When you select a cell this delegate method is triggered.当您选择一个单元格时,会触发此委托方法。

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


        UITableViewCell *theUITableViewCell = [tableView cellForRowAtIndexPath:path];
        if (theUITableViewCell.selected == YES){
            self.tableView deselectRowAtIndexPath:<#(NSIndexPath *)#> animated:<#(BOOL)#>
            // Do more thing
        }else{
            // By default, it is highlighted for selected state
        }

 }

It's pseudo code.是伪代码。

I think that using the blue selection colouring for toggling may give a strange impression.我认为使用蓝色选择着色进行切换可能会给人一种奇怪的印象。 Why not use an accessory like a checkmark?为什么不使用像复选标记这样的附件? This is a much more familiar technique for selection toggling (be it multi-cell or single-cell).这是一种更熟悉的选择切换技术(无论是多单元格还是单单元格)。

See this answer for info: UITableView Multiple Selection有关信息,请参阅此答案: UITableView Multiple Selection

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if ([cell isSelected]) {
        // Deselect manually.
        if ([tableView.delegate respondsToSelector:@selector(tableView:willDeselectRowAtIndexPath:)]) {
            [tableView.delegate tableView:tableView willDeselectRowAtIndexPath:indexPath];
        }
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        if ([tableView.delegate respondsToSelector:@selector(tableView:didDeselectRowAtIndexPath:)]) {
            [tableView.delegate tableView:tableView didDeselectRowAtIndexPath:indexPath];
        }
        return nil;
    }

    return indexPath;
}

You can try this one, it's works for me (for single selection or multiple selections):你可以试试这个,它对我有用(单选或多选):

A. allocate a private NSMutableArray in viewDidLoad like: A. 在 vi​​ewDidLoad 中分配一个私有的 NSMutableArray 像:

@interface XXXViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
    NSMutableArray * selectedZoneCellIndexPaths;
}


- (void)viewDidLoad
{
    selectedZoneCellIndexPaths = [[NSMutableArray alloc] init];
}

B. in UITableViewDelegate didSelectRow add following lines B. 在 UITableViewDelegate didSelectRow 添加以下几行

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

     for (NSIndexPath * iter in selectedZoneCellIndexPaths)
     {
         if (indexPath.section == iter.section && indexPath.row == iter.row)
         {
             [tableView deselectRowAtIndexPath:indexPath animated:YES];
             [selectedZoneCellIndexPaths removeObject:iter];
             return;
         }
     }
     [selectedZoneCellIndexPaths addObject:indexPath];
     return;
}

Swift version of prisonerjohn's answer :斯威夫特版的囚犯约翰的回答:

public func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
  let cell = tableView.cellForRowAtIndexPath(indexPath)
  if (cell?.selected ?? false) {
    // Deselect manually.
    tableView.delegate!.tableView?(tableView, willDeselectRowAtIndexPath: indexPath)
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    tableView.delegate!.tableView?(tableView, didDeselectRowAtIndexPath: indexPath)
    return nil
  }
return indexPath;
}

From @prisonerjohn, in case someone wonders how to check if the delegate responds to the selector as @Patrick said, in Swift 3 :来自@prisonerjohn,以防有人想知道如何检查代表是否像@Patrick 所说的那样响应选择器,在Swift 3 中

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    guard let cell = tableView.cellForRow(at: indexPath) else {
        // Handle invalid cell
        ...
    }

    if cell.isSelected {
        if let respond = tableView.delegate?.responds(
            to: #selector(tableView(_:willDeselectRowAt:))),
            respond == true {
            tableView.delegate?.tableView!(tableView, willDeselectRowAt: indexPath)
        }

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

        if let respond = tableView.delegate?.responds(
            to: #selector(tableView(_:didDeselectRowAt:))),
            respond == true {
            tableView.delegate?.tableView!(tableView, didDeselectRowAt: indexPath)
        }

        return nil
    }

    return indexPath
}

Swift 5.斯威夫特 5.

In the UITableViewDelegate , it's as simple as follows:UITableViewDelegate ,简单如下:

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

I was after the same thing but @occulus' answer provided me the hint I was missing.我也在做同样的事情,但@occulus 的回答为我提供了我错过的提示。

It made me realize the way to get this done is to allow multiple selection in the table view and manually deselect previously selected rows when a new row is selected using one of the delegate methods.它让我意识到完成此操作的方法是允许在表视图中进行多项选择,并在使用其中一种委托方法选择新行时手动取消选择先前选择的行。

It seems quite natural that in single selection mode, the table view tries to leave one row selected as much as possible, thus not deselecting on tapping a selected row.在单选模式下,表格视图尝试尽可能多地选择一行,因此不会在点击所选行时取消选择,这似乎很自然。

Maybe my question wasn't specific enough, but the two answers are a bit wide of what I was after.也许我的问题不够具体,但是这两个答案与我所追求的有点宽泛。

It seems this isn't possible, and I went with a gesture recognizer of the cell to manually set selected / unselected state.似乎这是不可能的,我使用单元格的手势识别器手动设置选中/未选中状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM