在 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 节中的唯一数据。当我点击一个单元格时,willSelectCellAtIndexPath
和 didSelectCellAtIndexPath
被调用。正如预期的那样,当我再次点击同一个单元格时,didDeselectCellAtIndexPath
被调用。
即使在我开始将数据向下移动到第 1 部分并选择和取消选择之后,UITableView's
委托方法也会被适当地调用。
一旦将所有数据移至第 1 节,UITableView
就会开始表现出奇怪的行为。我最初可以选择一个呼叫,然后调用didSelectCellAtIndexPath
。但是,当我再次点击它时,永远不会调用 didDeselectCellAtIndexPath
。相反,对选定单元格的任何点击(我已经确认它确实是通过 [tableView indexPathsForSelectedCells]
或第 1 节中的任何其他单元格选择的,只会导致 willSelectIndexPath
和 didSelectIndexPath
被调用。
我在这些委托方法中有相当多的代码是不相关的(我相信)......我没有在任何地方显式更改单元格的选定状态。我已经发布了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