[英]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. 在 viewDidLoad 中分配一个私有的 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.