在 UITableView 中点击已选择的单元格时,将调用 willSelectCellAtIndexPath

Posted

技术标签:

【中文标题】在 UITableView 中点击已选择的单元格时,将调用 willSelectCellAtIndexPath【英文标题】:When tapping an already selected cell in a UITableView, willSelectCellAtIndexPath gets called 【发布时间】:2013-03-13 20:14:20 【问题描述】:

我有一个UITableView 有两个部分。基于用户交互(选择和取消选择),我的数据源和UITableView 被更新以在部分之间移动数据。最初它们是第 0 节中的唯一数据。当我点击一个单元格时,willSelectCellAtIndexPathdidSelectCellAtIndexPath 被调用。正如预期的那样,当我再次点击同一个单元格时,didDeselectCellAtIndexPath 被调用。

即使在我开始将数据向下移动到第 1 部分并选择和取消选择之后,UITableView's 委托方法也会被适当地调用。

一旦将所有数据移至第 1 节,UITableView 就会开始表现出奇怪的行为。我最初可以选择一个呼叫,然后调用didSelectCellAtIndexPath。但是,当我再次点击它时,永远不会调用 didDeselectCellAtIndexPath。相反,对选定单元格的任何点击(我已经确认它确实是通过 [tableView indexPathsForSelectedCells] 或第 1 节中的任何其他单元格选择的,只会导致 willSelectIndexPathdidSelectIndexPath 被调用。

我在这些委托方法中有相当多的代码是不相关的(我相信)......我没有在任何地方显式更改单元格的选定状态。我已经发布了willSelect 方法,如有需要可以发布更多。

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
if (remainingItemIsSelected && indexPath.section == 0) 
        //other cells in the remaining items section are selected and a cell from that section is being selected

        NSMutableIndexSet *arrayIndexesToBeDeleted = [[NSMutableIndexSet alloc] init];
        for (NSIndexPath *previouslySelectedIndexPath in [tableView indexPathsForSelectedRows]) 
            if (((ReceiptItem *)[self.remainingReceiptItems objectAtIndex:previouslySelectedIndexPath.row]).allocated == YES) 

                //update data sources
                NSLog(@"%@%i%@,%i",@"Section #:",previouslySelectedIndexPath.section,@" Row #:",previouslySelectedIndexPath.row);
                [self.assignedReceiptItems addObject:[self.remainingReceiptItems objectAtIndex:previouslySelectedIndexPath.row]];
                [arrayIndexesToBeDeleted addIndex:previouslySelectedIndexPath.row];

                //update index path arrays
                [self.receiptItemsToDeleteIndexPaths addObject:previouslySelectedIndexPath];
                [self.receiptItemsToAddIndexPaths addObject:[NSIndexPath indexPathForRow:self.assignedReceiptItems.count-1 inSection:1]];

                //update the pressed indexpath to equal to resulting indexpath to pass on to the didSelect method
                if (previouslySelectedIndexPath.row < indexPath.row) 
                    indexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:0];
                
            
        
        //Delete assigned items from the remaining receipt items
        [self.remainingReceiptItems removeObjectsAtIndexes:arrayIndexesToBeDeleted];
        //update table (move allocated item down)
        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:self.receiptItemsToDeleteIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView insertRowsAtIndexPaths:self.receiptItemsToAddIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView endUpdates];
        if (self.remainingReceiptItems.count == 0) 
            [tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
        
        //other cells in the remaining items section are selected and a cell from assigned items is being selected
        return nil;
    
    return indexPath;

【问题讨论】:

你是否设置了断点来检查方法是否被调用?还是您只考虑您的NSLog() 声明? 我设置了断点并确认没有调用didDeselectRowAtIndexPath。此外,我确认willDeselectRowAtIndexPath 也没有被调用。 【参考方案1】:

来自Documentation for UITableViewDelegate:

tableView:willDeselectRowAtIndexPath: 仅当用户尝试选择不同的行时存在现有选择时,才会调用此方法。为先前选择的行向委托发送此方法。

如果您仔细考虑这一点,您会发现您遇到的是预期的行为。点击选中的行不会在该行上调用will/didDeselctRowAtIndexPath

相反,您可以在 didSelectRowAtIndexPath 中为所选行处理此问题,即在此处取消选择。

可能的替代方案

话虽如此,我认为您正在滥用UITableView 类。它真的不是为了做这些动人的事情而设计的。毫无疑问,您已经注意到自己必须编写大量代码才能完成这项工作——这正是您遇到棘手错误的原因。

在我看来,一个更简洁(最终更灵活)的解决方案是拥有两个单独的表(或其他)视图,它们通过代表相互通知datasource 的更改。设置它可能需要更多的工作,但肯定会少很多麻烦。

【讨论】:

谢谢。有趣的是,如果您将 allowsMultipleSelection 设置为 YES,那么上述文档将不会保留(点击选定的单元格)调用 will/didDeselectRowAtIndexPath。我想尽可能干净/灵活地做到这一点,但我看不出单独的表视图如何解决这个问题。在 tableview 委托方法中,我现在不需要条件来确定哪个 UITableView 正在调用,而不是为 section 值设置条件?我是否需要为每一个与它们所包含的 ViewController 的 .m 文件设置不同的数据源和委托? 无需为多个表视图处理单个数据源(这是可能的 - 参见例如 Apple 的搜索结果控制器代码)的最简洁方法是拥有一个控制器来控制两个表视图控制器。

以上是关于在 UITableView 中点击已选择的单元格时,将调用 willSelectCellAtIndexPath的主要内容,如果未能解决你的问题,请参考以下文章

删除和插入具有不同高度的单元格时,UITableView 动画故障

在 UITableView (swift2) 中选择单元格时更新/重新加载 ViewController

为 iOS 选择 TableView 单元格时视图已更改

UIPopOverController + UITableView - 选择单元格时隐藏弹出框

在选择表格视图单元格时更改按钮的标题

UITableView 选择单元格时所有组件都更改了背景颜色