Reputation: 21
I am currently developing an application which contains a UITableView. The UITableView contains custom cells. Inside Cell I have Provided a UIbutton which will be used for multiple row selection. In tableView Currently i have 30 rows and it is working fine but, when i click on the button in the first row, The button in the 6th, 11th, 16th, 21st, 26th row also gets clicked and if click the second row after that next row gets clicked(i.e. 7th, 12th and so on...).
The code is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
//
// Create the cell.
//
cell =
[[[UITableViewCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier]
autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
indicatorImage = [UIImage imageNamed:@"NotSelected.png"];
indicatorHighImage = [UIImage imageNamed:@"IsSelected.png"];
selectbtn = [UIButton buttonWithType:UIButtonTypeCustom];
selectbtn.frame = CGRectMake(30,122,20,20);
[selectbtn setImage:indicatorImage forState:UIControlStateNormal];
selectbtn.tag = rowCount++;
[cell addSubview:selectbtn];
[selectbtn addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
-(IBAction)buttonClicked:(UIButton *)button
{
if([button isSelected])
{
[button setImage:indicatorImage forState:UIControlStateNormal];
[button setSelected:NO];
}
else
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Custom Button Pressed"
message:[NSString stringWithFormat: @"You pressed the custom button on cell #%i", button.tag]//pathToCell.row + 1]
delegate:self cancelButtonTitle:@"Great"
otherButtonTitles:nil];
[alertView show];
[alertView release];
[button setImage:indicatorHighImage forState:UIControlStateNormal];
[button setSelected:YES];
}
return;
}
Upvotes: 0
Views: 2095
Reputation: 40995
Okay, first of all, you're setting your button images incorrectly. To set the button states for selected and unselected, you don't change the image every time the button is pressed, you just do this when the button is created:
[button setImage:indicatorImage forState:UIControlStateNormal];
[button setImage:indicatorHighImage forState:UIControlStateSelected];
Notice the forState parameter - this lets you specify what state the image will be displayed for, that way the button will automatically display the other image when you set its selected property. In the buttonClicked method, you can now just say:
button.selected = !button.selected; // toggle selection state
Now the second problem, where where selecting one button selects others is due to the way that table cells are recycled within a table. If you set some properties on one cell (e.g. selecting a button) that cell will be re-used multiple times in the table and it will keep that state. A table with 100 rows doesn't contain 100 cells, it has maybe 10 cells and as you scroll it just keeps reusing those same 10 over and over.
For this reason, you can't store state information inside table cells. You need to back your table with an array of model objects, and each time the cellForRowAtIndexPath method is called you need to reset the cell properties from the object in your array with the equivalent index.
Also, some of the things you are doing inside the if (cell == nil) { ... }
clause in your cellForRowAtIndexPath method need to be moves outside of the if statement because otherwise they will only be set the first time the cell is created and won't be set again when it is re-used.
so your cellForRowAtIndexPath method should look something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell =
[[[UITableViewCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier]
autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
selectbtn = [UIButton buttonWithType:UIButtonTypeCustom];
[selectbtn setImage:[UIImage imageNamed:@"NotSelected.png"] forState:UIControlStateNormal];
[selectbtn setImage:[UIImage imageNamed:@"IsSelected.png"] forState:UIControlStateSelected];
selectbtn.frame = CGRectMake(30,122,20,20);
[cell addSubview:selectbtn];
[selectbtn addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
//get a model object from the array
MyModelObject *object = [myBackingArray objectAtIndex:indexPath.row];
//get the button and set its properties
UIButton *button = [cell.subviews lastObject];
button.tag = rowCountindexPath.row;
button.selected = object.mySelectedStateProperty;
return cell;
}
Note that MyModelObject, myBackingArray and object.mySelectedStateProperty are placeholders for a new class you will create as a model for your cell data and an array of those objects stored in your view controller to act as a permanent place to store your cell states.
Upvotes: 2