Iphone: Checkmarks in UITableview get mixed up when scrolling - iphone

I have a bit of a problem where my check marks that i apply to my rows in my UITableView get all mixed up when i scroll. Im pretty sure this has to do with how the iphone reuses the cells and when i scroll away from on that has a check mark it probably puts it back in when i gets a chance.
Could someone please give me some tips on how I might avoid this or possibly take a look at my methods and see if anything looks off?
I was thinking that maybe I could save each row selection that the user made and then check to see which rows were being displayed to make sure the correct ones got the checkmark but I could'nt see a way to do so.
Thanks so much.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
[cell setAccessoryView:nil];
}
NSMutableArray *temp = [[NSMutableArray alloc]init];
for (int j = 0; j < [listOfRowersAtPractice count]; j++) {
if ([[differentTeams objectAtIndex:indexPath.section] isEqualToString:[[rowersAndInfo objectForKey:[listOfRowersAtPractice objectAtIndex:j]]objectForKey:#"Team"]]) {
[temp addObject:[listOfRowersAtPractice objectAtIndex:j]];
}
}
[cell.cellText setText:[temp objectAtIndex:indexPath.row]];
[temp removeAllObjects];
[temp release];
// Set up the cell...
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType != UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}

Yes save the state of the row which is selected and in cellforrowatindexpath after you get the cell reset it to default state and check the state of the row and change the state.
EDIT:
You can create a NSMutabaleArray with number of items equal to the number of items in your datasource which is the name temp in your code.
On select you can actually change the value at that index to some text like #"selected" in the above created array.
In your cellforrowatindexpath you can check this text if its selected or unselected and then change the property of the cell. Its like maintaining a bitmap state for selected and unselected states.

Give this a go :
static NSString *CellIdentifier = [NSString stringWithFormat:#"Cell %d",indexPath.row];
I had the same problem on one of my app's.
As for the check marks, are you using a core data store at all?
If you are use the following....
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *item = [[self fetchedResultsController] objectAtIndexPath:indexPath];
if ([[item valueForKey:#"checks"] boolValue]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[cell.textLabel setTextColor:[UIColor redColor]];
[cell.detailTextLabel setTextColor:[UIColor redColor]];
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
[cell.textLabel setTextColor:[UIColor blackColor]];
[cell.detailTextLabel setTextColor:[UIColor blackColor]];
}
}
And......
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
if ([[selectedObject valueForKey:#"checks"] boolValue]) {
[selectedObject setValue:[NSNumber numberWithBool:NO] forKey:#"checks"];
} else {
[selectedObject setValue:[NSNumber numberWithBool:YES] forKey:#"checks"];
}
[managedObjectContext save:nil];
}

You need to reset/clear all settings in the cell whenever you reuse the cell.
So here, right after you get the cell,
you need to do something like
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
[cell setAccessoryView:nil];
}
cell.accessoryType = UITableViewCellAccessoryNone // This and other such calls to clean up the cell

You need refresh the accessoryType of cell, because the cell is reused then it inherited the accessoryType from a reused Cell, this is the solution:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Refresh acessory for cell when tableview have many cells and reuse identifier
if([self.tableView.indexPathsForSelectedRows containsObject:indexPath]){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.textLabel.text = #"Your text cell";
return cell;
}

it worked for me..
in cell for row at index path i had created a checkbox button..
after everytym tableview is scrolled cellForRowAtIndexPath Method gets called
hence i had to add condition in cellForRowAtIndexPath to check whether a cell has a checked or unchecked button
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.prepTimeLabel.text = [prepTime objectAtIndex:indexPath.row];
checkbox = [[UIButton alloc]initWithFrame:CGRectMake(290, 5, 20, 20)];
[checkbox setBackgroundImage:[UIImage imageNamed:#"checkbox_empty.png"]
forState:UIControlStateNormal];
[checkbox addTarget:self action:#selector(checkUncheck:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:checkbox];
if(selectedRows.count !=0)
{
if([[selectedRows objectAtIndex:indexPath.row]integerValue]==1)
{
[checkbox setImage:[UIImage imageNamed: #"checkbox_full.png"] forState:UIControlStateNormal];
}
else
{
[checkbox setImage:[UIImage imageNamed: #"checkbox_empty.png"] forState:UIControlStateNormal];
}
}
return cell;
}
method to define selection of checkbox is as
- (IBAction)checkUncheck:(id)sender {
UIButton *tappedButton = (UIButton*)sender;
NSLog(#"%d",tappedButton.tag);
if ([[sender superview] isKindOfClass:[UITableViewCell class]]) {
UITableViewCell *containerCell = (UITableViewCell *)[sender superview];
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:containerCell];
int cellIndex = cellIndexPath.row;
NSLog(#"cell index%d",cellIndex);
[selectedRows insertObject:[NSNumber numberWithInt:1] atIndex:cellIndex];
}
NSLog(#"%#",selectedRows);
if([tappedButton.currentImage isEqual:[UIImage imageNamed:#"checkbox_empty.png"]])
{
[sender setImage:[UIImage imageNamed: #"checkbox_full.png"] forState:UIControlStateNormal];
}
else
{
[sender setImage:[UIImage imageNamed: #"checkbox_empty.png"] forState:UIControlStateNormal];
}
}
do not forget to initialize selectedRows array..
happy coding...!!!

Related

How to maintain state of selection of row in table view?

i am a beginner in xcode. I am creating a questionnaire type list with multiple rows in scroll. But when I select a row and scroll it doesn't retains its state and when I come back, it also loses its selection. So anyone please kindly let me know how to achieve that,i have tried something like this,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(val==1)
{
checkedArr=[[NSMutableArray alloc] init];
for (int i = 0; i<17; i++)
{
[checkedArr addObject:#"1"];
}
NSLog(#"Checked arr size %i",[checkedArr count]);
return 17;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%i",indexPath.row];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil)
{
cell= [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:14.0];
}
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:18.0];
UIView *selectionColor = [[UIView alloc] init];
selectionColor.backgroundColor = [UIColor colorWithRed:99/255.0f green:209/255.0f blue:248/255.0f alpha:1.0];
cell.selectedBackgroundView = selectionColor;
if([[checkedArr objectAtIndex:indexPath.row] isEqual:#"0"])
{
cell.accessoryView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tick.png"]];
NSLog(#"checkedArr 0000000");
}
else if ([[checkedArr objectAtIndex:indexPath.row] isEqual:#"1"])
{
cell.accessoryView=nil;
NSLog(#"checkedArr 111111");
}
cell.textLabel.frame=CGRectMake(75.0, 50.0, 150.0, 20.0);
cell.textLabel.text=[listArray objectAtIndex:indexPath.row];
NSLog(#"Checked arr size %i",[checkedArr count]);
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
cell=[questionTable cellForRowAtIndexPath:indexPath];
[checkedArr replaceObjectAtIndex:indexPath.row withObject:#"0"];
if([[checkedArr objectAtIndex:indexPath.row] isEqual:#"0"])
{
cell.accessoryView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tick.png"]];
NSLog(#"checkedArr 0000000");
}
else if ([[checkedArr objectAtIndex:indexPath.row] isEqual:#"1"])
{[questionTable deselectRowAtIndexPath:indexPath animated:YES];
cell.accessoryView=nil;
NSLog(#"checkedArr 111111");
}
NSLog(#"Val is %i",val);
NSLog(#"selected is %#",[listArray objectAtIndex:indexPath.row]);
// NSLog(#"Checked arr descripton %#",[checkedArr description]);
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryView = UITableViewCellAccessoryNone;
}
In my application i used same code for check mark as accessoryType,check this.
take it in .h file mutable array arSelectedRows;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
//Do anything you want for cell here
if([arSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arSelectedRows addObject:indexPath];
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[arSelectedRows removeObject:indexPath];
}
NSLog(#"arSelectedRows are :%#",arSelectedRows);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
EDIT
//if you want only single check mark
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[arSelectedRows removeAllObjects];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arSelectedRows addObject:indexPath];
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[arSelectedRows removeObject:indexPath];
}
NSLog(#"arSelectedRows are:%#",arSelectedRows);
[self.tableview reloadData];//Reload your tableview here
}
it will help you.
First your cellForRowAtIndexPath method create new cell each time whenever you scroll up/down tableView, it is very bad for memory management.
Just remove [questionTable deselectRowAtIndexPath:indexPath animated:YES] in your cellForRowAtIndexPath method
I think you need to use this api below:-
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
If you are using dynamic cells, and updating your row with some kind of class variable like a NSArray, you might have set your variable to weak instead of strong.

How can i dynamically change the UISwitch of UITableView?

I have a UItableView where every UITableViewCell is containing a UISwitch .Now my question is when i will click in one switch then how can i OFF other switches of the UITableViewCell
In my code i have already made the view and i can ON/OFF the switches.But i want to OFF all other switches except my selected switch.
Please some help me by giving an example or source code example.
With Best Regards
Edit
My Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
switchview = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switchview;
switchCondition = NO;
[switchview setOn:NO animated:YES];
[switchview addTarget:self action:#selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventValueChanged];
[switchview release];
}
if(switchCondition == YES){
[switchview setOn:YES animated:YES];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.backgroundColor = [UIColor clearColor];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[cellValueArray objectAtIndex:indexPath.row]];
return cell;
}
- (void)updateSwitchAtIndexPath:(UISwitch*)sender {
if(sender.on){
switchCondition = YES;
[table reloadData];
}
}
Update your data model used by the table's data source, then reload the table (or at least the visible rows). This will cause each row to reload and each switch will get updated with the latest data.
Edit: Here's an updated version of your code:
You need an instance variable to track the state of each switch. Create an array to hold the YES and NO values. In the code below I will assume there is an instance variable named switchConditions of type NSMutableArray that has been setup with NSNumber objects representing the YES and NO values for each row. This is similar to your cellValueArray. You should also get rid of your switchView and switchCondition instance variables.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitchView *switch = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switch;
[switchview addTarget:self action:#selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventValueChanged];
[switch release];
}
UISwitchView *switch = (UISwitchView *)cell.accessoryView;
switch.tag = indexPath.row; // This only works if you can't insert or delete rows without a call to reloadData
BOOL switchState = [switchConditions[indexPath.row] boolValue];
switch.on = switchState; // this shouldn't be animated
cell.contentView.backgroundColor = [UIColor clearColor];
cell.textLabel.text = cellValueArray[indexPath.row];
return cell;
}
- (void)updateSwitchAtIndexPath:(UISwitch*)switch {
NSInteger row = switch.tag;
if (switch.on){
// This switch is on, turn all of the rest off
for (NSUInteger i = 0; i < switchConditions.count; i++) {
switchConditions[i] = #NO;
}
switchConditions[row] = #YES;
[self.tableView reloadData];
} else {
switchConditions[row] = #YES;
}
}

How To implement UITableView with multiple buttons in same UITableViewCell?

I want to implement UITableView Where I want to have 3 buttons in each UITableViewCell, I want to assign Tittles to each buttons Dynamically, if am having all titles in 'title_array
' say then how can I get the index to an array for giving tittles to each buttons in each UITableViewCell ?
here is my code ,
which is not working,
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// printf("\ncellForRowAtIndexPath\n");
//static NSString *CellIdentifier = #"Cell";
NSString *CellIdentifier = [NSString stringWithFormat:#"identifier_%d", indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
//cell.textLabel.text=#"Golbal VC";
int x=50;
if (indexPath.row == 0) {
sample = 0;
}else{
if (sample == [titles_array count]-1);
else sample += 2;
}
for(int i =0; i <2 ; i++){
UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(x,50,300, 300)];
[btn setBackgroundImage:[UIImage imageNamed:#"Canada.gif"] forState:UIControlStateNormal];
[btn addTarget:self action:#selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:btn];
UILabel *tit_lbl=[[UILabel alloc]initWithFrame:CGRectMake(10,10,280,45)];
[tit_lbl setText:[titles_array objectAtIndex:sample]];
[btn addSubview:tit_lbl];
[tit_lbl release];
UILabel *src_lbl=[[UILabel alloc]initWithFrame:CGRectMake(10,65,280,25)];
[src_lbl setText:[source_array objectAtIndex:sample]];
[btn addSubview:src_lbl];
[src_lbl release];
x=x+350;
/*if(index == [titles_array count]-1)
break;
index++;
*/
}
return cell;
}
You should have to try using this link and create custom cell accordingly and put three buttons in your UITableViewCell XIB file... This is the simplest method for doing this... and assign tag to each button in XIB...
http://blog.webscale.co.in/?p=284
http://www.e-string.com/content/custom-uitableviewcells-interface-builder
http://adeem.me/blog/2009/05/30/iphone-sdk-tutorial-part-6-creating-custom-uitableviewcell-using-interface-builder-uitableview/
you should use titleArray with NSDictionary objects, where you can provide title to your buttons according to the position in the cell( jus for example, you can use anything to identify your buttons).
- (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] autorelease];
}
NSDictionary *dict = (NSDictionary*)[titleArray objectAtIndex:indexPath.row];
UILabel *tit_lbl=[[UILabel alloc]initWithFrame:CGRectMake(10,10,280,45)];
[tit_lbl setText:[dict valueForKey:#"titleLabel"]];
[btn addSubview:tit_lbl];
[tit_lbl release];
UILabel *src_lbl=[[UILabel alloc]initWithFrame:CGRectMake(10,65,280,25)];
[src_lbl setText:[dict valueForKey:#"sourceLabel"]];
[btn addSubview:src_lbl];
[src_lbl release];
return cell;
}
Hope it helps..

'reset' table view cell's content

my app has a bug, and i believe its because I'm not reseting the cells content. The apple docs say
The table view’s data source implementation of tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell.
Could someone please explain how to do this, or point me to a tutorial? Thank you in advance!
My cellForRow
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
addBtn = [[UIButton alloc]init];
addBtn =[UIButton buttonWithType:UIButtonTypeRoundedRect];
[addBtn setFrame:CGRectMake(220,10,25,55)];
[addBtn addTarget:self action:#selector(addLabelText:) forControlEvents:UIControlEventTouchUpInside];
[addBtn setTitle:#"+" forState:UIControlStateNormal];
[addBtn setEnabled:YES];
[cell addSubview:addBtn];
subBtn = [[UIButton alloc]init];
subBtn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[subBtn setFrame:CGRectMake(260,10,25,55)];
[subBtn addTarget:self action:#selector(subtractLabelText:) forControlEvents:UIControlEventTouchUpInside];
[subBtn setTitle:#"-" forState:UIControlStateNormal];
[subBtn setEnabled:YES];
[cell addSubview:subBtn];
}
//cellText.hidden=!self.editing;
cell.textLabel.textColor = [UIColor orangeColor];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.imageView.image = [imageArray objectAtIndex:indexPath.row];
cell.textLabel.text = [number objectAtIndex:indexPath.row];// <------ Is this line in the right place?
cell.textLabel.text = #"1"; // <---- Is this line in the right place?
return cell;
}
It's pretty simple. You provide the call cellForRowAtIndexPath in your code. In it, you either provide a brand new cell, or you reuse a cell that the OS has chucked into memory. Basically, you code looks like this:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
[[cell textLabel] setText:[pickerData objectAtIndex:indexPath.row]];
cell.accessoryType = (indexPath.row == currentValueOfIndex ) ?
UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
The part under the comment // Configure the cell is where you have to reset your cells content. Since it can either be a new cell, or a recycled cell, it will either have no information, or the information from another cell where it was recycled from. In both cases, you provide the cell's text and accessories and anything else you want to use each time the cell is called. Basically, it's a callback to you to provide a cell, either a brand new one, or a recycled one, and you have to stuff the right info for the cell it's going to be (based on the index path). Hope I made this clear enough.
If you're adding views programmatically to the cell, you should do the following for cleaning them:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
for (UIView * v in cell.contentView.subviews) {
[v removeFromSuperview]
}
//Configure your cell
return cell;
}
See the comments in the code below...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// this is where you want to configure your generic cell
// for example, if EVERY cell needs to have a disclosure indicator, you could do
cell.accessoryType = UITableViewAccessoryTypeDisclosurseIndicator;
}
// this is where you want to put code that would or could be unique to a cell
// for example, if you wanted to put the row number you could do:
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
// you would put this here and not in the above if statement because the value of the textLabel changes for different cells
return cell;
}

iphone: how to add checkboxes to a uitableviewcell?

I just can't seem figure out how to do this hopefully someone here can help me. In my tableview i want to add checkboxes to each cell and if you touch the checkbox a checkmark appears and a specific action is supposed to happen. but if you just touch the cell a different action is supposed to happen. Does anyone have an idea how to do this?? I started doing the following. But i think my approach creates memory leaks and i don't know how to perform an action only for the button that was pressed instead for all of them.....
It would be great if someone could help me out....
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSArray *tempArray = [[exerciseNames objectAtIndex:indexPath.section] objectForKey:#"rowValues"];
UIButton *checkButton = [UIButton buttonWithType:UIButtonTypeCustom];
checkButton.tag = indexPath.row;
[checkButton setFrame:CGRectMake(10, 10, 23, 23)];
if (checkButtonPressed == YES) {
[checkButton setBackgroundImage:[[UIImage imageNamed:#"checked.png"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];
}
else {
[checkButton setBackgroundImage:[[UIImage imageNamed:#"unchecked.png"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];
}
[checkButton addTarget:self action:#selector(checkAction) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:checkButton];
cell.imageView.image = [UIImage imageNamed:#"unchecked.png"];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.text = [NSString stringWithFormat:#"%# (%#)", [[tempArray objectAtIndex:indexPath.row] objectForKey:#"full"], [[tempArray objectAtIndex:indexPath.row] objectForKey:#"short"]];
// Set up the cell...
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"CellWithSwitch"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellWithSwitch"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont systemFontOfSize:14];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
cell.textLabel.text = #"Sound Effects";
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
I would try subclassing UITableViewCell and make each cell the target of the buttons action. That way when the button is pressed, the event will be handled by the cell object, not the table controller. If you don't like that, you could try using the tag your assigning to the button to make a distinction. To do that, make your button selector be
checkAction:(UIButton *)_btn {}
and when you add the target,
[checkButton addTarget:self action:#selector(checkAction:) forControlEvents:UIControlEventTouchUpInside];
(notice the : at the end of the #selector())
I haven't tried the second way, but I think it would work.
In Cocoa Touch, a UISwitch is the UI paradigm equivalent for a checkbox on a desktop UI.
Your checkAction handler can check which control called it, and only change that one control.