Getting/Setting UITextField value in a table cell - iphone

For my current project i need to have a table in which contains textfield in each cell, the number of cells and textfield must be dynamic, it's depends on the number of data in a MutuableArray. I have the textfield in cells working, but i can't get/set the textfield value. I wonder if you guys can help me out or at least correct me what I did wrong? Thank's alot in advance. See code snippets below:
// Adds textfield into cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSUInteger row = indexPath.row;
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:row];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
BOOL bShowSelection = ([curIndex.HasVasteWaarden isEqualToString:#"false"]);
if (bShowSelection) {
bShowSelection = !([curIndex.DataType isEqualToString:#"Datum"]);
}
if ([indexPath section] == 0) {
if (bShowSelection) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
UITextField *editField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
editField.adjustsFontSizeToFitWidth = YES;
editField.textColor = [UIColor blackColor];
editField.placeholder = curIndex.Naam;
editField.keyboardType = UIKeyboardTypeDefault;
editField.returnKeyType = UIReturnKeyNext;
editField.backgroundColor = [UIColor whiteColor];
editField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
editField.autocapitalizationType = UITextAutocapitalizationTypeNone; // no auto capitalization support
editField.textAlignment = UITextAlignmentLeft;
editField.clearButtonMode = UITextFieldViewModeNever; // no clear 'x' button to the right
editField.tag = [curIndex.UID intValue];
[editField setEnabled: YES];
[cell addSubview:editField];
[editField release];
}
}
return cell;
}
In some case i'm using popovercontroller to display list of data. User can select a value uit of the popup. This code is executed when there is a value selected:
- (void)selectedValue:(NSString *) value {
//---update value of the text field ---
//The first attempt it doesn't put the text to text field
//static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//
//if (cell == nil) {
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//}
// second attempt it crashes
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:curRow.row];
int index = [curIndex.UID intValue];
UITextField *textField = (UITextField *) [curCell viewWithTag: index];
if (textField) {
[textField setText:value];
}
[textField release];
[self.popOverController dismissPopoverAnimated:YES];
}
When cell is selected I'm making sure that the cell is saved for use later.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:indexPath.row];
if (!curIndex) {
return;
}
curRow = indexPath; // saves the selected row
if ([curIndex.VasteWaarden count] > 0) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
curCell = cell; // saves the selected cell
CGRect frame = [cell.superview convertRect:cell.frame toView:self.view];
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
detailViewController.delegate = self;
self.popOverController = [[[UIPopoverController alloc] initWithContentViewController:detailViewController] autorelease];
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:indexPath.row];
self.detailViewController.Values = curIndex.VasteWaarden;
[self.popOverController presentPopoverFromRect:frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
Again thank's alot in advance.
Cheers,
Inoel

In the second code snippet you are releasing the textField. You shouldn't do this because you haven't retained it. Because viewWithTag: simple gets a reference to the text field it doesn't retain the textField. So you are releasing it more times that it has been retained, so the retainCount reaches 0 and the textfield is dealloced from memory. Then when you attempt it the second time there is no textfield in the memory.
Just remove the:
[textField release];
From the second code snippet. If you don't understand why, then read some articles about memory management (just google it). It takes some time to understand it fully, at least I know it took me a while :)

Related

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;
}
}

cell.textLabel not getting resized

I'm trying to create a Settings for our app. I'm not sure what is happening here. I have a UITableViewSyleGrouped and in each section of the table, there is 1 row. For my particular row, it shows the person's name. If you click on it, then it pushes to a new tableView that has the list of people to choose from, then when you pop back, the label gets updated, but the label is truncated when I go from a smaller name to a bigger name. I'm trying to create a Settings for our app. Some of the fields look like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
if (tableView == _settingsTableView) {
UITableViewCell *cell = nil;
NSNumber *aSection = [_tableArray objectAtIndex:indexPath.section];
if ([aSection integerValue] == SOUNDS)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"SwitchCell"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SwitchCell"] autorelease];
}
cell.textLabel.text = #"Sounds";
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switchView;
[switchView setOn:[[Settings sharedInstance] playSounds] animated:NO]; // initialize value from Settings
[switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[switchView release];
}
else if ([aSection integerValue] == PERSON) {
cell = [tableView dequeueReusableCellWithIdentifier:#"PersonCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"PersonCell"] autorelease];
}
Person *p = [_personArray objectAtIndex:row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", p.firstName, p.lastName];
NSLog(#"cL: %#", NSStringFromCGRect(cell.textLabel.frame));
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
My PERSON section gives the user the ability to change People. That code in didSelectRowAtIndexPath is
else {
Person *p = [_personArray objectAtIndex:row];
NSUInteger oldRow = [_lastIndexPath row];
if (oldRow != row) {
dmgr.currentPerson = p;
// Put checkmark on newly selected cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Remove checkmark on old cell
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:_lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
[_settingsTableView deselectRowAtIndexPath:_lastIndexPath animated:YES];
self.LastIndexPath = indexPath;
// Update the cell
NSIndexPath *path = [NSIndexPath indexPathForRow:0 PERSON];
UITableViewCell *theCell = [_settingsTableView path];
theCell.textLabel.text = [NSString stringWithFormat:#"%# %#", p.firstName, p.lastName];
[theCell setNeedsDisplay];
NSLog(#"ceLL: %#", NSStringFromCGRect(theCell.textLabel.frame));
}
}
What happens is the label is truncated until I click on the label. (e.g. John D... instead of John Doe). Why does the label not get updated?
I tried looking at the frames, and I'm not sure if that has something to do with it or not. My output is:
cL: {{0, 0}, {0, 0}}
ceLL: {{10, 11}, {76, 21}}
The textLabel field of a UITableViewCell is a regular UILabel. You can set this property to cause it to scale down the text to fit:
theCell.textLabel.adjustsFontSizeToFitWidth = YES;
You can also set a minimum font size
theCell.textLabel.minimumFontSize = whatever
Take a look at the Documentation on UILabel it will help you a lot.

Data lose On UITableViewCell When UITableView Scrolling?

I am trying to implement UITableview based application. In my tableView their is 10 Section and each section having one row.
I want implement each section have Different type of ContentView(1-8 same ContentView 9th section Different ContentView). I did this code For that.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 10;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
UITextField *textField;
UITextView *textView;
NSUInteger section=[indexPath section];
if(section == 9){
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1]autorelease];
textView=[[UITextView alloc]initWithFrame:CGRectMake(5, 5, 290, 110)];
[textView setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor
]];
[textView setTag:([indexPath section]+100)];
[cell.contentView addSubview:textView];
}else{
textView=(UITextView*)[cell.contentView viewWithTag:([indexPath section]+100)];
}
return cell;
}else {
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]autorelease];
textField=[[UITextField alloc]initWithFrame:CGRectMake(5, 5, 290, 50)];
[textField setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor]];
[textField setTag:([indexPath section]+100)];
[cell.contentView addSubview:textField];
}else{
textField=(UITextField*)[cell.contentView viewWithTag:([indexPath section]+100)];
}
return cell;
}
return nil;
}
My problem are:
1. After type some thing in the UITextField/UITextView i am scrolling in the UITableView. that time all data in the UITableViewCell(UITextField/UITextView) was lose, except last cell data.
2. If i create cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Instead of
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
Data will repeating . How can i over come this problem?
This line:
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
Should never appear in your data source cellForRowAtIndexPath method.
Apart from that, your code is OK, except that you are not setting the text field value anywhere. You need a model (such as an array of strings for the 10 textfield values). This model should be updated when the textfields are edited, and in your method above you copy the value back out of the model and into the textfield's text property:
textfield.text = [self.modelArray objectAtIndex:indexPath.section];
The table pools and reuses cells in an unpredictable fashion, so that subview of a cell that just scrolled off the bottom might reappear next at the top, or might be disposed of.
This is why you saw it partially work. The cell's subviews work okay until their cell gets reused or unloaded, then things move to the wrong place or data disappears.
The solution is that your table's datasource needs to hold onto it's own data. This is usually an array representing your model. Your case is a little unusual because you are using the text controls in your table as inputs, rather than display, which is more typical.
I suggest doing it like this:
// in #interface
#property (nonatomic, retain) NSMutableArray *sections;
// in #implementation
#synthesize sections=_sections;
// at some point before the view appears
self.sections = [NSMutableArray array];
for (int i=0; i<10; i++) {
UIControl *textControl;
if (i<9) {
textControl=[[UITextView alloc]initWithFrame:CGRectMake(5, 5, 290, 110)];
} else {
textControl=[[UITextField alloc]initWithFrame:CGRectMake(5, 5, 290, 50)];
}
[textControl setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor]];
[textControl setTag:i+100];
[sections addObject:textControl];
[textControl release];
}
Now your cellForRowAtIndexPath is a little simpler:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
NSUInteger section=[indexPath section];
if(section == 9) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell==nil) {
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1]autorelease];
}
} else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell==nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]autorelease];
}
}
// who knows what subview this cell has? it might not have one, or it might have the wrong one
// just clean it up to be certain
for (UIView *view in cell.subviews) {
[view removeFromSuperView];
}
// get the textControl we set up for _this_ section/cell
UIControl *textControl = [self.sections objectAtIndex:section];
// now we have a fresh cell and the right textControl. drop it in
[cell addSubview:textControl];
return cell;
}
hey the reason is you are doing this things when cell is nil ? but you are not writing any code when cell is not nil.
look at this example , in this example i am adding image view in tableview cell , hence you can add textviews or any other views like this
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imgView;
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100,0,100,62)];
[imgView setImage:[UIImage imageNamed:#"img.png"]];
imgView.tag = 55;
[cell.contentView addSubview:imgView];
[imgView release];
}
else
{
imgView = (id)[cell.contentView viewWithTag:55];
}
so as showin here imgView = (id)[cell.contentView viewWithTag:55]; you have to give tag to you and write code showing above in else..
Let you try to make the cell labels and textviews by using following code. It works for me.
if (tagvalue ==3) {
static NSString *CellIdentifier = #"Cell3";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
}
lbl7 = [[UILabel alloc] init];
[lbl7 setFont:[UIFont boldSystemFontOfSize:20]];
[cell.contentView addSubview:lbl7];
lbl7.backgroundColor = [UIColor clearColor];
lbl7.frame = CGRectMake(120, 5, 0, 40);
lbl7.tag = 70;
[lbl7 release];
lbl8 = [[UILabel alloc] init];
[lbl8 setFont:[UIFont boldSystemFontOfSize:18]];
[cell.contentView addSubview:lbl8];
lbl8.backgroundColor = [UIColor clearColor];
lbl8.textColor = [UIColor grayColor];
lbl8.frame = CGRectMake(120, 50, 0, 40);
lbl8.tag = 80;
[lbl8 release];
lbl7 = (UILabel*)[cell.contentView viewWithTag:70];
lbl8 = (UILabel*)[cell.contentView viewWithTag:80];
lbl7.text = [[rowsarray objectAtIndex:row]objectForKey:#"name"];
lbl8.text = [[rowsarray objectAtIndex:row]objectForKey:#"flavour"];
[lbl7 sizeToFit];
[lbl8 sizeToFit];
return cell;
}
if (tagvalue ==4) {
static NSString *CellIdentifier = #"Cell4";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
lbl9 = [[UILabel alloc] init];
[lbl9 setFont:[UIFont boldSystemFontOfSize:20]];
[cell.contentView addSubview:lbl9];
lbl9.backgroundColor = [UIColor clearColor];
lbl9.frame = CGRectMake(120, 5, 0, 40);
lbl9.tag = 90;
[lbl9 release];
lbl10 = [[UILabel alloc] init];
[lbl10 setFont:[UIFont boldSystemFontOfSize:18]];
[cell.contentView addSubview:lbl10];
lbl10.backgroundColor = [UIColor clearColor];
lbl10.textColor = [UIColor grayColor];
lbl10.frame = CGRectMake(120, 50, 0, 40);
lbl10.tag = 100;
[lbl10 release];
lbl9 = (UILabel*)[cell.contentView viewWithTag:90];
lbl10 = (UILabel*)[cell.contentView viewWithTag:100];
lbl9.text = [[rowsarray objectAtIndex:row]objectForKey:#"name"];
lbl10.text = [[rowsarray objectAtIndex:row]objectForKey:#"flavour"];
[lbl9 sizeToFit];
[lbl10 sizeToFit];
return cell;
}
I had same issue. Its not the problem with table class. The issue is at the place where you are calling this tableviewcontroller. First make the object of this call in .h and then allocate in .m, thats it..
When I was declaring in viewdidload like tbl *t = [self.storyboard...];, I was also facing the same problem. But when I put tbl *t; in .h problem solved.

Objective-C: How to retain inputs and also tag names when UItextFields scrolled off?

My App is placing questions and according to the question, placing either UITextField or UISwitch.
When a user input texts it automatically detects which textField and placing the texts accordingly.
It works well but when the items are scrolled off, it removes the user inputs and tag names as well, and when displayes the area placing a new items on top of that.
So when a user input texts it stores it into the old textField.
I would like to know how to prevent it from this issue.
Is there any suggestion? Thanks in advance.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
NSLog(#"-------------cellForRowAtIndexPath---------------");
cell_id = [qid objectAtIndex:[indexPath row] ];
static NSString *CellIdentifier = #"Cell";
label = nil;
cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[self configureLabel];
[[cell contentView] addSubview:label];
}
dict = [qtext objectAtIndex:[indexPath row]];
celltext = [NSString stringWithFormat:#"%#\n\n\n",[[dict allKeys] objectAtIndex:0]];
dict = [qtype objectAtIndex:[indexPath row]];
type = [[dict allKeys] objectAtIndex:0];
//place the question
cell.textLabel.text = celltext;
NSLog(#"celltext=%#",celltext);
if([type isEqualToString:#"devider"]){
[self configureDevider];
}else{
[self configureCell];
}
if([cell_id intValue] == ([qid count])){
tabledone = #"Yes";
}
tableView.backgroundColor=[UIColor clearColor];
tableView.opaque=NO;
tableView.backgroundView=nil;
NSString *a = [arrAllheight objectAtIndex:[indexPath row]];
allheight +=thisheight;
thisheight =[a intValue];
if([type isEqualToString:#"YN"]){
DCRoundSwitch *ynSwitch = [[DCRoundSwitch alloc] initWithFrame:CGRectMake(220,thisheight-40,80,27)] ;
ynSwitch.onText=#"Yes";
ynSwitch.offText=#"No";
[answers addObject:ynSwitch];
[cell addSubview:ynSwitch];
[ynSwitch setTag:[cell_id intValue]];
[ynSwitch addTarget:self action:#selector(setAnswersForRoundSwitches:) forControlEvents:UIControlEventValueChanged];
i++;
}else if([type isEqualToString:#"freetext"]){
//When the done button was clicked, remove the keybords from the screen
[self makeTextField];
[rtxtfield addTarget:self action:#selector(setAnswersfortextFields:) forControlEvents:UIControlEventEditingDidEndOnExit];
// [rtxtfield value];
}else if([type isEqualToString:#"dropdown"]){
picc = [picker_array objectForKey:[[NSString alloc] initWithFormat:#"%d",cell_id]];
//Choose an array for this textField
// [self getPickerArray];
[self makeTextField];
//[rtxtfield addTarget:self action:#selector(setAnswersfortextFields:) forControlEvents:UIControlEventEditingDidEndOnExit];
//When the done button was clicked, remove the keybords from the screen
[rtxtfield addTarget:self action:#selector(textFieldReturn:) forControlEvents:UIControlEventEditingDidEndOnExit];
//Get the tag for picker
[rtxtfield addTarget:self action:#selector(getTag:) forControlEvents:UIControlEventTouchDown];
//Display picker
[rtxtfield addTarget:self action:#selector(acsheet:) forControlEvents:UIControlEventTouchDown];
//set Tag for the textField
[rtxtfield setTag:[cell_id intValue]];
NSLog(#"rtxtfield tag=%d",rtxtfield.tag);
}
if([type isEqualToString:#"devider"]){
[self caliculateHeightofCell];
}else{
[self caliculateHeightofCell];
}
return cell;
}
Save the state of your controls in your data model as soon as they change. So, maybe your model is an array of questions, and each question has an instance variable that can hold the answer. Your view controller is probably both the table data source and table delegate, and you should make it the target of any controls in the cells, too. That is, when you set up a new cell in your -tableView:cellForRowAtIndexPath:, make the view controller the target of the UITextField or UISwitch in the cell. When the user changes either of those controls, then, the change will trigger an action in the view controller, and the view controller can retrieve the new value of the control and store it in the corresponding question in the data model.
If you take this approach, you never have to worry about questions scrolling out of view. As soon as the question scrolls back into view, -tableView:cellForRowAtIndexPath: will be called for that row again, and you'll have all the information you need to reconstitute that cell.
Save the text to the dataSource. UITableViewCells must not contain any state information.
Implement something similar to this:
- (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];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(2, 2, 200, 40)];
textField.tag = 999;
textField.delegate = self;
textField.placeholder = #"Enter text here";
[cell.contentView addSubview:textField];
}
UITextField *textField = (UITextField *)[cell.contentView viewWithTag:999];
textField.text = [self.dataSource objectAtIndex:indexPath.row];
/* configure cell */
return cell;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
UIView *contentView = [textField superview];
UITableViewCell *cell = (UITableViewCell *)[contentView superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self.dataSource replaceObjectAtIndex:indexPath.row withObject:textField.text];
}
Do not add views outside of if (cell == nil)!
If you have different type of cells use a different CellIdentifier! Like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SwitchCellIdentifier = #"SwitchCell";
static NSString *TextFieldCellIdentifier = #"TextFieldCell";
UITableViewCell *cell = nil;
if (/* current cell is a text field cell */) {
cell = [tableView dequeueReusableCellWithIdentifier:TextFieldCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TextFieldCellIdentifier];
// add textField
}
// configure cell...
}
else if (/* current cell is a switch cell */) {
cell = [tableView dequeueReusableCellWithIdentifier:SwitchCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SwitchCellIdentifier];
// add switch
}
// configure cell...
}
return cell;
}
I took a day to fix the problem, but I've finally got it right:
Sorry it's a long code cause it's using textField, DCRoundSwitch, and pickerView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"-----------------cellForRowAtIndexPath---------------");
Questions *q = [qtext objectAtIndex:indexPath.row];
NSLog(#"question=%#",q.question);
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *SwitchCellIdentifier = #"SwitchCell";
static NSString *TextFieldCellIdentifier = #"TextFieldCell";
static NSString *DropDownFieldCellIdentifier = #"DropDownCell";
cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:TextFieldCellIdentifier];
if ([q.question_type isEqualToString:#"freetext"]) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TextFieldCellIdentifier];
if (cell == nil) {
[self makeTextField];
[cell.contentView addSubview:rtxtfield];
cell.textLabel.text = q.question;
}
[self makeTextField];
[self configureCell];
[self configureLabel];
cell.textLabel.text = q.question;
[cell.contentView addSubview:rtxtfield];
rtxtfield.text = [appDelegate.dataSource objectAtIndex:indexPath.row];
rtxtfield.tag=[indexPath row];
}else if([q.question_type isEqualToString:#"YN"]){
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SwitchCellIdentifier];
if (cell == nil) {
[self makeDCRoundSwitch];
[ynSwitch setTag:[indexPath row]];
cell.textLabel.text = q.question;
[self configureLabel];
[self configureCell];
}
[self makeDCRoundSwitch];
[ynSwitch setTag:[indexPath row]];
cell.textLabel.text = q.question;
[self configureLabel];
[self configureCell];
[ynSwitch addTarget:self action:#selector(ynSwitchDidEndEditing:) forControlEvents:UIControlEventValueChanged];
if([[appDelegate.dataSource objectAtIndex:indexPath.row] isEqualToString:#"Yes"]){
[ynSwitch setOn:YES animated:YES];
} else{
[ynSwitch setOn:NO animated:YES];
}
rtxtfield.tag=[indexPath row];
} else if([q.question_type isEqualToString:#"dropdown"]){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DropDownFieldCellIdentifier];
if (cell == nil) {
[self makeTextField];
[cell.contentView addSubview:rtxtfield];
cell.textLabel.text = q.question;
}
[self makeTextField];
[self configureCell];
[self configureLabel];
cell.textLabel.text = q.question;
[cell.contentView addSubview:rtxtfield];
picc=q.question_array;
//When the done button was clicked, remove the keybords from the screen
[rtxtfield addTarget:self action:#selector(textFieldReturn:) forControlEvents:UIControlEventEditingDidEndOnExit];
//Get the tag for picker
[rtxtfield addTarget:self action:#selector(getTag:) forControlEvents:UIControlEventTouchDown];
//Display picker
[rtxtfield addTarget:self action:#selector(acsheet:) forControlEvents:UIControlEventTouchDown];
//set Tag for the textField
[rtxtfield setTag:[indexPath row]];
// AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
rtxtfield.text = [appDelegate.dataSource objectAtIndex:indexPath.row];
rtxtfield.tag=[indexPath row];
}
[self makeTextField];
rtxtfield.tag=[indexPath row];
tableView.backgroundColor=[UIColor clearColor];
tableView.opaque=NO;
tableView.backgroundView=nil;
return cell;
}
try this
label = nil;
//cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[self configureLabel];
[[cell contentView] addSubview:label];
//}
comment your code like that and tell me what happens

data of uitableviewcell overlapping with each other on scrolling

I have a tableview with four sections and all of the sections have two textfields and a label in different rows. I have added some text as placeholder of textfield. Initially the data appears fine but when I scroll the tableview the cell starts to have overlapped data.
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];
}
if(indexPath.row==0) {
UITextField *txtName = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 300, 30)];
txtName.placeholder = #"Full Name";
[cell.contentView addSubview:txtName];
[txtName release];
}
else if(indexPath.row==1) {
UITextField *txtEmail = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 300, 30)];
txtEmail.placeholder = #"Email";
[cell.contentView addSubview:txtEmail];
[txtEmail release];
}
else if(indexPath.row==2){
cell.textLabel.text = #"Select Date of Birth";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell...
return cell;
}
thanks in advance
Pankaj
You need to create your text fields only in the block of code that inits the cell. Remember that the table view recycles cells so as you scroll off the screen you get a reused and recycled cell that already has a textfield. You are then creating a new textfield and overlaying the new textfield on the existing one, hence you get overlapping.
here is your code properly refactored
- (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];
//create the textField here, and we will reuse it and reset its data for each row.
UITextField *txtField = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 300, 30)];
[cell.contentView addSubview:txtField];
txtField.tag=110; //should declare a constant that uniquely defines your textField;
[txtField release];
}
// Configure the cell...
//ok, now we retrieve the textField and set its data according to the row.
UITextField *txtField = (UITextField *)[cell.contentView viewWithTag:110];
if(indexPath.row==0) {
txtField.placeholder = #"Full Name";
}
else if(indexPath.row==1) {
txtField.placeholder = #"Email";
}
else if(indexPath.row==2){
txtField.placeholder = nil; //? did you mean to set something here?
cell.textLabel.text = #"Select Date of Birth";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
I have just modified the previous one for missing an else condition which made an bad access error. The modified code is below:
You need to create your text fields before the block of code that inits the cell and init and add this text field in the block of code that inits the cell. Remember that the table view recycles cells so as you scroll off the screen you get a reused and recycled cell that already has a textfield. You are then creating a new textfield and overlaying the new textfield on the existing one, hence you get overlapping.
here is your code properly refactored
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITextField *txtField;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//init the textField here, and we will reuse it and reset its data for each row.
txtField = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 300, 30)];
[cell.contentView addSubview:txtField];
txtField.tag=110; //should declare a constant that uniquely defines your textField;
[txtField release];
}
else{
// if the textfield is alread created and now dequed
//ok, now we retrieve the textField and set its data according to the row.
txtField = (UITextField *)[cell.contentView viewWithTag:110];
}
if(indexPath.row==0) {
txtField.placeholder = #"Full Name";
}
else if(indexPath.row==1) {
txtField.placeholder = #"Email";
}
else if(indexPath.row==2){
txtField.placeholder = nil; //? did you mean to set something here?
cell.textLabel.text = #"Select Date of Birth";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}