Reputation: 19323
I have a transparent table view (UIViewController with subview UIImageView, and another subview UITableView on top of the UIImageView sibling with background = clearColor, UITableViewCells background = clearColor). I also want taps on the cells to toggle the cell's accessoryType between checkmark and none. If I modify the UITableViewCell's accessoryType in tableView:didSelectRowAtIndexPath:, sometimes (30-50% of the time, both on the ios4.1 simulator and on a 3GS iphone running os4.1) when toggling from accessoryType None to accessoryType checkmark the checkmark image is painted against an opaque white background instead of a transparent background. If instead I reload the table (where the accessoryType is also set appropriately for each cell) the transparency works correctly 100% of the time.
Is this a bug? Or is modifying a cell in tableView:didSelectRowAtIndexPath: not the right thing to do, and that row should be reloaded instead? Or is there something else I'm missing?
edit: Here's my didSelectRowAtIndexPath code that shows the undesirable behavior:
edit 2: One more detail of what's happening. It's the very tail end of the deselect animation where the problem happens. The checkmark appears and is displayed properly & transparently while the deselect animation is running and the blue selection is gradually fading out. After the deselect animation finishes and the blue is all gone, maybe 1/10 of a second after the selection color is completely gone, is when the checkmark accessory "automagically" turns opaque with no further user input.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ( self.editing )
{
}
else
{
[self.myTableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
// toggle the selection status of the selected row
//
NSNumber *rowObj = [NSNumber numberWithUnsignedInt:indexPath.row];
if ( [self.selectedRows containsObject:rowObj] )
{
// currently selected, now de-select
//
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedRows removeObject:rowObj];
}
else
{
// currently unselected, now select
//
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedRows addObject:rowObj];
}
}
}
Upvotes: 2
Views: 3017
Reputation: 1448
This post hasn't been updated in 4 months but I figured I would submit my solution as it seems to work and could help somebody else with a similar problem.
Everything happens in the didSelectRowAtIndexPath method. The self.view I call is a tableView (so replace it with your tableView's name, e.g. self.tableView)
// let's go through all the cells to update them as I only want one cell at a time to have the checkmark next to it
for (int i=0; i<[self.detailsArray count]; i++) {
// whenever we reach the cell we have selected, let's change its accessoryType and its colour
if (i == indexPath.row) {
// that's the row we have selected, let's update its
UITableViewCell *cell = [self.view cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.textLabel.textColor = [UIColor colorWithRed:51.0f/255.0f green:102.0f/255.0f blue:153.0f/255.0f alpha:1.0f];
}
// if it isn't the cell we have selected, let's change it back to boring dark colour and no accessoryType
else {
UITableViewCell *cell = [self.view cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.textLabel.textColor = [UIColor darkTextColor];
}
}
// don't forget to deselect the row
[self.view deselectRowAtIndexPath:indexPath animated:YES];
Upvotes: 1
Reputation: 2261
I think it's cleaner if you move the toogle selection piece of code to
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
and on didSelectRowAtIndexPath call to
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
This way you will reload only the selected row as soon as it is selected, and no need for calling reloadData. Hope this helps!
Upvotes: 2
Reputation: 19323
In debugging another problem in an unrelated project with a custom table row selection animation, I found that if the cell selection style is not UITableViewCellSelectionStyleNone, then any changes to the cell performed in didSelectRowAtIndexPath are subject to glitches and other desirable results (the changes made to cell N do not show up until cell != N is selected later, and animations performed on the cell never show up at all). When I changed the selection style to UITableViewCellSelectionStyleNone, then all visual cell changes made in didSelectRowAtIndexPath show up right away without problems.
Upvotes: 0
Reputation: 2947
this UITableViewDelegate method:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
is called right before displaying a cell. Modifying your accessory view there should work.
Upvotes: 0