Reputation: 10733
I created a fresh project (Xcode 4, Master-Detail application) just to see if I'm doing something wrong, but I still have the same problem. I want to call -reloadData
when the user deselects a cell, so this is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(@"%s", __PRETTY_FUNCTION__);
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __PRETTY_FUNCTION__);
[tableView reloadData];
}
-(NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __PRETTY_FUNCTION__);
return indexPath;
}
The problem is that didDeselectRowAtIndexPath
and willDeselectRowAtIndexPath
don't seem to be called. Is this the expected behavior? The docs for tableView:didDeselectRowAtIndexPath:
state
Tells the delegate that the specified row is now deselected.
so I guess that it should work as I thought.
Upvotes: 28
Views: 33604
Reputation: 25785
One source of this issue is setting isSelected
directly on the table view cell, rather than telling the table view to select the cell via selectRow(at:animated:scrollPosition:)
or deselect it via deselectRow(at:animated:)
.
The cell's isSelected
property is not the source of truth that the table view uses to determine whether to call the delegate's didDeselect
method (although a cell whose isSelected
is set does seem to prevent the table view from calling the delegate's didSelect
method—meaning that the cell can get in a state where it is impossible to select or deselect via the UI).
Upvotes: 0
Reputation: 3521
First of all, you have to set allowsMultipleSelection
is true
and set delegate
by below code
self.tableView.allowsMultipleSelection = true
self.tableView.delegate = self
If you use tableView.reloadData()
in didSelectRowAt
delegate method, remove this.
in your custom cell, use selected method.
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
//write your code here for selection method
}
By this method, your cell state is selected. If you again click on selected cell, then didDeSelect delegate method will call automatically.
Upvotes: 0
Reputation: 14379
For me it's started working by adding ->super.setSelected(selected, animated: animated)
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)//This was missing
}
Upvotes: 1
Reputation: 21
You just have to set the selection to be "Multiple Selection" as Xcode allow you to deselect the cells in this mode only.
Upvotes: 2
Reputation: 1067
When any cell is selected the first time, the -[UITableViewDelegate tableView:didDeselectRowAtIndexPath:]
method is not called, but the -[UITableViewDelegate tableView:didSelectRowAtIndexPath:]
. Just after selecting one more cell, the didDeselectRowAtIndexPath
is called right after the didSelectRowAtIndexPath
.
This is OK.
But if you have to show a cell as selected at the begining, (e.q. using UITableViewCellAccessoryCheckmark
), then, after selecting another cell you probably want the didDeselectRowAtIndexPath
method being called the first time, to deselect the previous cell.
The solution!
You have to call the -[UITableView selectRowAtIndexPath:animated:scrollPosition:]
in the -[UITableViewDataSource tableView:cellForRowAtIndexPath:]
to notify that a wanted cell is already selected.
Objective-C
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// saving the current selected row
SelectedRow = indexPath.row;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
#pragma mark - UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
// preventing selection style
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = "Some text";
if (indexPath.row == SelectedRow) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// just wanted to make it selected, but it also can scroll to the selected position
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
return cell;
}
Swift 3.1
// MARK: - UITableViewDelegate
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)!
cell.accessoryType = UITableViewCellAccessoryType.checkmark
selectedRow = indexPath.row
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)!
cell.accessoryType = UITableViewCellAccessoryType.none
}
// MARK: - UITableViewDataSource
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
// preventing selection style
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.textLabel?.text = "some text"
if (indexPath.row == selectedRow) {
cell.accessoryType = UITableViewCellAccessoryType.checkmark
// just wanted to make it selected, but it also can scroll to the selected position
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.none)
}
return cell
}
Upvotes: 4
Reputation: 1353
A clean way of solving this problem is to do the following:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath)
// Do your cell setup work here...
//If your cell should be selected...
if cellShouldBeSelected {
tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: UITableViewScrollPosition.None)
}
return cell
}
This solves this entire problem of a cell not responding to being deselected after a tableView.reloadData()
call happens.
Upvotes: 6
Reputation: 1727
I know this is an old question but I just ran into the same problem.
If you use
[tableView reloadData]
Then The table data is reloaded and no rows are selected behind the scenes - meaning
only
didSelectRowAtIndexPath
is ever called. I hope this helps someone who comes across this problem.
Upvotes: 10
Reputation: 8134
I think it's just simple mistake! Why don't you use following:
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
Instead of using just "tableView" in that line?
I guess, and pretty sure that above line would give you the solution!
hope this helped you, if you looked back at your old question!!!
Kudos! :)
Upvotes: 0
Reputation: 1806
Set allowsMultipleSelection
for that tableview to TRUE
self.tableView.allowsMultipleSelection = YES;
Upvotes: 1
Reputation: 12009
One other quirk that I've found — in IOS 5.1, at any rate — is that if you call reloadData
on the table, you won't get didDeselectRowAtIndexPath
for any selected rows. In my case, I adjust the cell layout slightly depending on whether it's selected or not, so I needed to manually do that work prior to reloading the table data.
Upvotes: 12
Reputation: 4819
If you call deselectRowAtIndexPath:animated:
, the delegate methods tableView:willDeselectRowAtIndexPath:
and tableView:didDeselectRowAtIndexPath:
message are not sent.
Upvotes: 55
Reputation: 29767
the documentation of tableView:willDeselectRowAtIndexPath:
also says that
This method is only called if there is an existing selection when the user tries to select a different row. The delegate is sent this method for the previously selected row. You can use UITableViewCellSelectionStyleNone to disable the appearance of the cell highlight on touch-down.
It not worked for we when I used UITableViewCellSelectionStyleNone
.
Upvotes: 25