UITableViewCellAccessory Disappears When Scrolled Off Screen
I have a UITableView filled with objects. In the didSelectRowAtIndexPath method i have a UITableViewCellAccessoryCheckmark appear when the row is selected and disappear when unselected.
Heres the code for the didSelectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *curCell = [beerTable cellForRowAtIndexPath:indexPath];
if (curCell.accessoryType == UITableViewCellAccessoryCheckmark) {
[curCell setAccessoryType:UITableViewCellAccessoryNone];
compareCount = (compareCount - 1);
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
NSString *objBeer = [searchResults objectAtIndex:indexPath.row];
[compareBeers removeObject:[searchResults objectAtIndex:indexPath.row]];
[compareCarbs removeObject:[开发者_开发百科carbAmount objectAtIndex:[beerNames indexOfObject:objBeer]]];
}
else {
[compareBeers removeObject:[beerNames objectAtIndex:indexPath.row]];
[compareCarbs removeObject:[carbAmount objectAtIndex:indexPath.row]];
}
}
else {
[curCell setAccessoryType:UITableViewCellAccessoryCheckmark];
compareCount = (compareCount + 1);
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
NSString *objBeer = [searchResults objectAtIndex:indexPath.row];
[compareBeers addObject:[searchResults objectAtIndex:indexPath.row]];
[compareCarbs addObject:[carbAmount objectAtIndex:[beerNames indexOfObject:objBeer]]];
}
else {
[compareBeers addObject:[beerNames objectAtIndex:indexPath.row]];
[compareCarbs addObject:[carbAmount objectAtIndex:indexPath.row]];
}
}
if (compareCount > 0) {
if (compareOn == YES){
}
else {
compareButton.enabled = YES;
UIImage *image = [UIImage imageNamed:@"redbutton.png"];
[compareButton setImage:image];
}
}
else {
compareButton.enabled = NO;
[compareButton setImage:nil];
[compareButton setCustomView:nil];
}
}
I also have this as my cellForIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (CustomCell *) currentObject;
break;
}
}
}
// Setting separate tables correctly....
return cell;
}
My problem is that when the cell that is selected is scrolled out of view the checkmark associated with that value is now gone when back into view.
What should I do to keep the Checkmark from disappearing?
Thanks
Your cells get re-used as you scroll through the data (that's what the dequeueReusableCellWithIdentifier does). Your cell that got a checkmark in didSelectRowAtIndexPath gets recycled for a different row and no longer has any connection to the checked row.
You need to set/unset the accessory view in cellForRowAtIndexPath so when the checked rows scroll back into view, they get checked appropriately.
for anyone wanting a more generic approach and for multiple selected cells
First create an (NSMutableArray *)selectedCells to keep track of the selected cells. Next implement the 2 delegate methods
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//add the checkmark to cell when selected
if ([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryNone){
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
//once selected add that selected cell to the selectedCells array
[self.selectedCells addObject:@(indexPath.row) ];
}
AND
-(void)tableView:(UITableView *)tableView
didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
//set the accessory type back to none
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark){
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
//remove the selected cells index from the selectedCells array
[self.selectedCells removeObject:@(indexPath.row) ];
}
Now when ever you select a cell a checkmark is added and that indexPath.row is stored in to an NSMutableArray. When you deSelect that cell it removes the checkmark and removes it from the array. Meaning the array will only hold cells that are checked.
We then use that array to give the cell the correct accessoryType in the cellForRowAtIndexPath method. This method is called every time the tableView requires a cell we tell it wether that sell requires to have a checkMark when created or not.
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
//Create an NSNumber to hold the row of the cell to be created
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:indexPath.row];
//then ask the array if the selectedCells array has that object.
//if it does then that cell needs a checkmark when created.
if ([self.selectedCells containsObject:rowNsNum]){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else { cell.accessoryType = UITableViewCellAccessoryNone;
}
[cell.textLabel setText:@"your contents"];
}
return cell;
}
UITableViewCell are recycled when you scroll. So when you scroll the tableView down and up again, the cell you see may be different from the previously visible cell.
You need to reset the status of a cell everytime in cellForRowAtIndexPath. You code has this comment area // Setting separate tables correctly....
This is where you do the setting. When this is called, check if the cell is supposed to show a checkmark, and set it accordingly
Try to store selected index in a array or dictionary for the selected cell in didSelectRow method, and in cellForRowAtIndexPath check if that index is available in array then checkmark the cell with setting accesoryType. Hope you understand
This is what I find to work best:
(just any code between "Add this" and "End Add this")
Also, make sure you change "(Your Number ofRows)" to an object that either returns an int, or is an int itself. Such as myCustomArray.count, or 24.
//In .h file add this
NSMutableArray *indexArray;
//in .m file
- (void)viewDidLoad {
//Add this
indexArray = [[NSMutableArray alloc] init];
int i;
for (i = 0; i <= (Your Number ofRows); i++) {
[indexArray addObject:[NSNumber numberWithDouble:0]];
}
NSLog(@"indexArray = %@",indexArray);//You can check the console now to see if you have an array of "zeros"
//End Add this
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *curCell = [beerTable cellForRowAtIndexPath:indexPath];
if (curCell.accessoryType == UITableViewCellAccessoryCheckmark) {
[curCell setAccessoryType:UITableViewCellAccessoryNone];
compareCount = (compareCount - 1);
//Add this
[indexArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithDouble:0]];
//End Add this
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
NSString *objBeer = [searchResults objectAtIndex:indexPath.row];
[compareBeers removeObject:[searchResults objectAtIndex:indexPath.row]];
[compareCarbs removeObject:[carbAmount objectAtIndex:[beerNames indexOfObject:objBeer]]];
}
else {
[compareBeers removeObject:[beerNames objectAtIndex:indexPath.row]];
[compareCarbs removeObject:[carbAmount objectAtIndex:indexPath.row]];
}
}
else {
[curCell setAccessoryType:UITableViewCellAccessoryCheckmark];
compareCount = (compareCount + 1);
//Add this
[indexArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithDouble:1]];
//End Add this
if (tableView == [[self searchDisplayController] searchResultsTableView]) {
NSString *objBeer = [searchResults objectAtIndex:indexPath.row];
[compareBeers addObject:[searchResults objectAtIndex:indexPath.row]];
[compareCarbs addObject:[carbAmount objectAtIndex:[beerNames indexOfObject:objBeer]]];
}
else {
[compareBeers addObject:[beerNames objectAtIndex:indexPath.row]];
[compareCarbs addObject:[carbAmount objectAtIndex:indexPath.row]];
}
}
if (compareCount > 0) {
if (compareOn == YES){
}
else {
compareButton.enabled = YES;
UIImage *image = [UIImage imageNamed:@"redbutton.png"];
[compareButton setImage:image];
}
}
else {
compareButton.enabled = NO;
[compareButton setImage:nil];
[compareButton setCustomView:nil];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (CustomCell *) currentObject;
break;
}
}
}
// Setting separate tables correctly....
//Add this
if ([[indexArray objectAtIndex:indexPath.row] doubleValue] == 1) {
cell.accesoryType = UITableViewCellAccesoryTypeCheckmark;
} else {
cell.accesoryType = UITableViewCellAccesoryTypeNone;
}
//End Add this
return cell;
}
精彩评论