i want to create an 10 text field on same cell index path how can i do that , get values from them and i want to do this dynamically in storyboard can any one suggest me how can i do this.
if (cell != nil) {
cell = [[tableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
for (int i=indexPath.row ;i< [self.dataArray count];i++) {
UITextField *valueTextField = [[UITextField alloc] initWithFrame:CGRectMake(8,10,88,21)];
valueTextField.tag = indexPath.row;
[valueTextField borderStyle];
valueTextField.backgroundColor =[UIColor grayColor];
valueTextField.delegate = self;
valueTextField.placeholder=#"Placeholder";
[cell.contentView addSubview:valueTextField];
cell.editingAccessoryType = YES;
}
}
Related
I have created a UITextField in a UITableView. I type the data in and close the keyboard. However when I scroll down and hide the UITextField and then scroll back up again, the 'UITextField' data is duplicated as seen below:
Original Load of View:
Typed in Data:
After hidden textfield and then started editing again:
- (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];
}
if ([indexPath section] == 0) { // Email & Password Section
cell.textLabel.text = #"Subject";
} else {
cell.textLabel.text = #"Task";
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if ([indexPath section] == 0) {
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
return cell;
}
Like Richard said, cells are reused (that's what the identifier purpose is), and that's why you test in your tableView:cellForRowAtIndexPath: for a nil value returned by dequeueReusableCellWithIdentifier:.
If a cell already exists (ie. was allocated earlier) and is not displayed anymore, dequeueReusableCellWithIdentifier: will use this cell to display the content of the newly appearing cell.
What you are doing is adding your UITextView every time your cells are displayed and not created. So each time a cell is gets scrolled out of the screen and a new cell pops in, you append a new UITextView in the cell. You should add subviews only in the if (cell == nil) part of your method. As the content of your cells are rather different, I'd recommend using two distinct identifiers.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifierForSection0 = #"Cell0";
static NSString *CellIdentifierForSection1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: [indexPath section] == 0 ? CellIdentifierForSection0 : CellIdentifierForSection1];
if (cell == nil) {
if ([indexPath section] == 0) { // Email & Password Section
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection0];
cell.textLabel.text = #"Subject";
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection1];
cell.textLabel.text = #"Task";
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
Note that this code is mainly for example purpose, and could be greatly reducted. Moreover, you should use subclass(es) of UITableViewCell like Richard suggested, as it will help organizing your code and make it more reusable.
BUT do NOT use drawRect: to add subviews. This is unnecessary and will impact performances. drawRect: should only be used if you intend to make real drawing like with CoreAnimation or CoreGraphics. Adding subview should be done in initWithFrame: or initWithCoder: depending of your use of Interface Builder or not.
Remember cells get reused, therefore the subviews are added each time it's reused. If you're going to add subviews to a cell you're best off creating a subclass of UITableViewCell and adding the subviews in the drawRect: method of that subclass. That way the modifications are part of the cell and aren't added each time the cell is reused.
In my app i am customised the UITableView Cell with four UITextViews. Whenever i added data to the tableview and reload it. The text in the UITableViewCell get override with the previous texts.
I tried different approaches but couldn't figure out what was the problem.
I am using TableView in View Controller.
Here is the Code i used in my table View cell?
if ( [tableView isEqual:self.tableActions])
{
//Setting the text empty
static NSString *CellIdentifier = #"ActionsIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
NSLog(#"Index Path %i",[indexPath row]);
ActionDetails *actiondetails = [actionArray objectAtIndex:[indexPath row]];
NSLog(#"Action Text %#",actiondetails.actions);
//Actions
actionText=[[UITextView alloc] initWithFrame:CGRectMake(10, 5, 230,30)];
actionText.font = [UIFont systemFontOfSize:17.0];
actionText.editable = NO;
actionText.textColor=[UIColor blackColor];
actionText.text = actiondetails.actions ;
actionText.userInteractionEnabled = NO;
actionText.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:actionText];
//Owner
ownerBy=[[UITextView alloc] initWithFrame:CGRectMake(230, 5, 230,30)];
ownerBy.font = [UIFont systemFontOfSize:17.0];
ownerBy.textColor=[UIColor blackColor];
ownerBy.textAlignment = UITextAlignmentCenter;
ownerBy.text = actiondetails.owner;
ownerBy.editable = NO;
ownerBy.userInteractionEnabled = NO;
ownerBy.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:ownerBy];
}
ScreenShot
Thanks for your help guys.
Much Appreciated.
This happened to me a other day, the solution that I came up with was removing all subview from the cell after creating the cell in the if statement.
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
if ([cell.contentView subviews]){
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
}
Remove cell identifier of Tableview otherwise take Customcell for the Tableview..
Just simple try this way :
{
//Setting the text empty
static NSString *CellIdentifier = #"ActionsIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
**// if(cell == nil) // comment this line in your code ,its work
// {**
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
**// }**
NSLog(#"Index Path %i",[indexPath row]);
ActionDetails *actiondetails = [actionArray objectAtIndex:[indexPath row]];
NSLog(#"Action Text %#",actiondetails.actions);
//Actions
actionText=[[UITextView alloc] initWithFrame:CGRectMake(10, 5, 230,30)];
actionText.font = [UIFont systemFontOfSize:17.0];
actionText.editable = NO;
actionText.textColor=[UIColor blackColor];
actionText.text = actiondetails.actions ;
actionText.userInteractionEnabled = NO;
actionText.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:actionText];
//Owner
ownerBy=[[UITextView alloc] initWithFrame:CGRectMake(230, 5, 230,30)];
ownerBy.font = [UIFont systemFontOfSize:17.0];
ownerBy.textColor=[UIColor blackColor];
ownerBy.textAlignment = UITextAlignmentCenter;
ownerBy.text = actiondetails.owner;
ownerBy.editable = NO;
ownerBy.userInteractionEnabled = NO;
ownerBy.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:ownerBy];
}
You are reusing the cell. Reused cell already has UITextview added to it.So you are overriding on it.
You must shift all your code of creating and adding UITextView to.
If(cell==nil)
{
}
After which you only need to set the Text to UITextview.
when your view did appear write reload your table view.
-(void)viewDidAppear:(BOOL)animated {
[tableView reloadData];
}
change your cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"S%1dR%1d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// your code
}
// your code
return cell;
}
for (id vw in [[cell contentView] subviews]) {
if ([vw isKindOfClass:[UILabel class]])
{
UILabel *label = (UILabel *)vw;
[label removeFromSuperview];
}
}
for (id vw in [cell subviews]) {
if ([vw isKindOfClass:[UILabel class]])
{
UILabel *label = (UILabel *)vw;
[label removeFromSuperview];
}
}
I have a UITableView with 8 cells(sections) in total in which 6 of them contain textFields as subviews and out of 2 one containing button and the other containing text view.Now I have got a problem here,as we are all aware that when ever the view appears only,the visible cells loads.So when my app gets loaded,I am able to view 5 cells,the first 4 containing text fields and the 5th cell with button.I can see the array count is 4 when i displayed it through logging in console i.e.
there are 4 objects in the array
Now after scrolling the table view,I can observe the following:
there are 6 objects in the array
So,what's happening is If I am to save the data entered in the table view,or say edit to make changes to existing data,I am forced to scroll the table view and enter the values in last cell too.So that cannot be the case always with the user because we can't expect him/her to scroll the table view and enter the complete form/table view cell entries.What ever changes he/she makes they will and just click done/save what ever it is..!
More over I am having a picker view as input view for last cell containing text field as subview.Hence in my picker view did select row method I am facing crash problem with last cell/section(textField as subview) containing a picker view here is my code snippet for the method:
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
switch (tagValues)
{
case 105:
{
self.textField = [self.fields objectAtIndex:3];
self.textField.text = [self.reminder objectAtIndex:row];
}
break;
case 107:
{
//Crash occurring in this case,sometimes its working wonder why
self.textField = [self.fields objectAtIndex:5];
self.textField.text = [self.group objectAtIndex:row];
}
break;
}
}
**Note**:I am using the same textField for adding as subview to all 6 cells,but each one with unique tags and own purpose,i.e. one for editing text using key board,one with date picker,one with general picker etc...
I wonder why some times after selecting values from picker view(last section cell) crashes some times and some times works fine.Some times it crashes at the above line commented in case 107,some times in main autorelease pool.Some time thread as shown in snap below:
So is there any way that we can load all cells at once so that all the text fields get added to array before scrolling.There cannot be any problem I believe
More Detailed EDITED CODE for understanding:
- (UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSString *identifier = #"UITableViewCell";
NSString *cellIdentifierF = nil;
static NSString *firstCellIdentifier = #"FirstCell";
static NSString *secondCellIdentifier = #"SecondCell";
static NSString *thirdCellIdentifier = #"ThirdCell";
static NSString *fourthCellIdentifier = #"FourthCell";
static NSString *fifthCellIdentifier = #"FifthCell";
static NSString *sixthCellIdentifier = #"SixthCell";
static NSString *seventhCellIdentifier = #"SeventhCell";
static NSString *eightCellIdentifier = #"EightCell";
if(indexPath.section == 0 && indexPath.row == 0)
{
cellIdentifierF = firstCellIdentifier;
}
else if(indexPath.section == 1 && indexPath.row == 0)
{
cellIdentifierF = secondCellIdentifier;
}
else if(indexPath.section == 2 && indexPath.row == 0)
{
cellIdentifierF = thirdCellIdentifier;
}
else if(indexPath.section == 3 && indexPath.row == 0)
{
cellIdentifierF = fourthCellIdentifier;
}
else if(indexPath.section == 4 && indexPath.row == 0)
{
cellIdentifierF = fifthCellIdentifier;
}
else if(indexPath.section == 5 && indexPath.row == 0)
{
cellIdentifierF = sixthCellIdentifier;
}
else if(indexPath.section == 6 && indexPath.row == 0)
{
cellIdentifierF = seventhCellIdentifier;
}
else if(indexPath.section == 7 && indexPath.row == 0)
{
cellIdentifierF = eightCellIdentifier;
}
UITableViewCell *cell = (UITableViewCell *)[atableView dequeueReusableCellWithIdentifier:cellIdentifierF];
atableView.backgroundColor = [UIColor clearColor];
textField = [[[UITextField alloc]initWithFrame:CGRectMake(15, 12, 300, 24)]autorelease];
textField.textColor = [UIColor whiteColor];
textField.delegate = self;
tagValues = textField.tag;
switch (indexPath.section)
{
case 0:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: firstCellIdentifier])
{
textField.placeholder = #"Enter name";
[self.textField setValue:[UIColor purpleColor]
forKeyPath:#"_placeholderLabel.textColor"];
textField.tag = 101;
textField.text = reminderInstance.Name;
textField.autocorrectionType = UITextAutocorrectionTypeNo;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
}
}
break;
case 1:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: secondCellIdentifier])
{
textField.tag = 102;
textField.text = reminderInstance.Event;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
}
}
break;
case 2:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: thirdCellIdentifier])
{
textField.placeholder = #"Click here to set date and time";
[self.textField setValue:[UIColor purpleColor]
forKeyPath:#"_placeholderLabel.textColor"];
textField.inputView = self.datePicker;
textField.text = reminderInstance.Date;
textField.tag = 103;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
}
}
break;
case 3:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: fourthCellIdentifier])
{
textField.tag = 105;
textField.text = reminderInstance.numDays;
textField.inputView = self.reminderPicker;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
}
}
break;
case 4:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: fifthCellIdentifier])
{
checkboxButton = [[[UIButton alloc] initWithFrame:CGRectMake(16,1,120, 44)]autorelease];
[checkboxButton setImage:[UIImage imageNamed:#"ewee.png"] forState:UIControlStateNormal];
[checkboxButton addTarget:self action:#selector(toggleButton:) forControlEvents:UIControlEventTouchUpInside];
NSString *one = reminderInstance.selString;
NSNumber* i = [NSNumber numberWithInt:[one intValue]];
BOOL isOn = [i boolValue];
if(isOn)
{
[checkboxButton setImage:[UIImage imageNamed:#"checkarrow.png"] forState:UIControlStateNormal];
}
else
{
[checkboxButton setImage:[UIImage imageNamed:#"ewee.png"] forState:UIControlStateNormal];
}
NSLog(#"String Val = %#",one);
[checkboxButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[checkboxButton setImageEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)];
[cell addSubview:checkboxButton];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(55, 10, 225, 24)];
label.text = #"Every Year";
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
[cell addSubview:label];
cell.textLabel.textColor = [UIColor whiteColor];
[label release];
}
}
}
break;
case 5:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: sixthCellIdentifier])
{
textField.placeholder = #"Enter the number here";
[self.textField setValue:[UIColor purpleColor]
forKeyPath:#"_placeholderLabel.textColor"];
textField.text = num;
textField.text = reminderInstance.number;
textField.tag = 106;
textField.userInteractionEnabled = YES;
textField.keyboardType = UIKeyboardTypeNumberPad;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
}
}
break;
case 6:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"reminderbuttonxl.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: seventhCellIdentifier])
{
cell.backgroundColor = [UIColor clearColor];
textView.clipsToBounds = YES;
textView = [[UITextView alloc]initWithFrame: CGRectMake(-2, -3, 307, 154)];
UIImageView *imgView = [[[UIImageView alloc]initWithFrame: textView.frame]autorelease];
imgView.image = [UIImage imageNamed: #"buttonbg_text.png"];
[textView addSubview: imgView];
[textView sendSubviewToBack: imgView];
textView.backgroundColor = [UIColor clearColor];
textView.delegate = self;
textView.tag = 11;
tagValues = textView.tag;
textView.textColor = [UIColor purpleColor];
[cell.contentView addSubview:textView];
textView.text = #"Your birthday wishes/other reminder body here";
NSLog(#"Value = %#",textView.text);
}
}
}
break;
case 7:
{
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
//Only add content to cell if it is new
if([cellIdentifierF isEqualToString: eightCellIdentifier])
{
textField.tag = 107;
textField.inputView = self.groupPicker;
tagValues = textField.tag;
textField.text = reminderInstance.remGroup;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
}
}
break;
default:
break;
}
int size = [fields count];
NSLog(#"there are %d objects in the array", size);
return cell;
}
I have made several attempts to find out what exactly is going wrong also I checked some questions here and there.But couldn't find any efficient/appr. answer or that solves my issue.
So anyone please help me with valuable suggestions or sample code snippets.
Thanks all in advance :)
It would make sense that there will be a lot of issues coming from the way you are building the form (which is actually the case)
what I've been doing myself when I need to build a such a form is to use build a normal view with all the controls whatever long it is and have that form in a scroll view and set its content size with the size of the view in it. that would let you have more control on how you want that form to look.
and I don't think I've seen an app using a tableview for a form entry.
you can use interface builder to build your form (just cheat on Xcode and make the main view and the scroll vew large enough so u can see everything on the builder, then resize it to the appropriate size when you are done)
It sounds like you might be better off not using a table view at all, but using a scroll view instead. If you really do have a fixed amount of things that you are going to display, you can just lay these out on a scroll view as views (instead of table cells) and your code will get a lot simpler.
If what you want out of the table view is just the appearance, you can simply use a background image that looks the way you want, and overlay the views and controls over that background. You should be able to do all of this in Interface Builder.
If you take this approach, the code in your view controller will now be just what you need to handle the text input and button presses, and you don't need to worry about a table view delegate or data source.
Although this seems to be already solved, what could have done as a "dirty hack" is to make the entire table scroll till bottom before performing any operation. Something like [myTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; This way it would be forced to load all the UITableCellView. Remember, this is not preferred way, but can work in case minimum code change is required.
What happens is that UITableView loads only the visible cells, and all the time that the UITableView is scrolled, the callback cellForRowAtIndexPath: is called. But let me get this straight. Why do you need a UITableView to make a form? And as I can see, you are loading one cell per section... And, you are only initializing the cell. What you should do. Subclass UITableViewCell and create your objects there.
then call like this:
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
Then you can call exactly the controller you want. And you have to control the behavior of your UITableView whenever it is scrolled. like this:
case 7:
{
if (cell == nil)
{
cell = [[[MyCustomCellEigth alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierF] autorelease];
cell.backgroundColor = [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"buttonbg-1.png"]];
/*this should be done in the Custom Cell init method
if([cellIdentifierF isEqualToString: eightCellIdentifier])
{
textField.tag = 107;
textField.inputView = self.groupPicker;
tagValues = textField.tag;
textField.text = reminderInstance.remGroup;
NSLog(#"Value = %#",textField.text);
[cell.contentView addSubview:textField];
[self.fields addObject:textField];
}
*/
}
else
{
//Control content
((MyCustomCell*)cell).myTextField.text = #"SOME TEXT";
}
}
break;
About the picker. It probably only works once you have scrolled all table, because it references a textField that will only be added to the Array once the correspondent cell become visible.
There isn't much more to do. But follow this and you should be fine. First, Subclass UITableViewCell. You can create the controls yourself programmatically or with a xib. This will give you more control over the cells itself. About the picker, instead of creating a array with controls, create it with the values it should have. Once someone has typed something, save it using the UITextFieldDelegate.
Hope it helps.
EDIT:
You must create a Subclass of the UITableViewCell. On Xcode, create a new file. Select objective-c Class. On the next screen, on the field subclass of, select UITableViewCell and name your cell accordingly. This will create a class that will override the initWithStyle:reuseIdentifier: method. Inside this method, you should put your init code.
like this:
#import <UIKit/UIKit.h>
#interface MyCustomCellOne : UITableViewCell
{
UITextField *textField;
}
#end
#import "MyCustomCellOne.h"
#implementation MyCustomCellOne
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
textField = [[UITextField alloc] initWithFrame:"YOUR FRAME"];
textField.tag = 107;
textField.text = #"SOME TEXT";
[self addSubview:textField];
}
return self;
}
First question on this site, although I have been around for a while behind the scenes. I have a problem that I have been racking my head on for the last two days and I hope someone can shed some light on it for me.
I have a UITableView, which is loaded from a SQL database. It has 15 entries in it. I have inserted an extra cell at the beginning of the UITableView. This extra cell is for a UITextField and UIButton which adds an item into the database.
When the view is loaded, the first cell with the custom objects shows fine, and the rest of the table is filled with items from the database and looks just how it should. However, when the UITableView is scrolled down so the first cell is out of view, then back up, it takes the value of the 11th row item and shows it over top the first cell.
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)popTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
static NSInteger NameTag = 1;
UITableViewCell *cell = [popTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
CGRect frame;
frame.origin.x =50;
frame.origin.y =10;
frame.size.height =22;
frame.size.width =275;
UILabel *nameLabel = [[UILabel alloc] initWithFrame:frame];
nameLabel.tag = NameTag;
nameLabel.opaque = YES;
nameLabel.textColor = [UIColor grayColor];
nameLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:nameLabel];
[nameLabel release];
}
int row = [indexPath row];
if (row == 0) {
UIButton *buttonLeft = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonLeft setFrame: CGRectMake( 205, 6, 40, 33)];
[buttonLeft addTarget:self action:#selector(addToList:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:buttonLeft];
//No Alloc for txtField, it is built in IB
[txtField setBorderStyle:UITextBorderStyleNone];
[txtField setFrame: CGRectMake( 17, 12, 180, 23)];
txtField.backgroundColor = [UIColor clearColor];
[txtField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
txtField.clearButtonMode = UITextFieldViewModeAlways;
}else{
UILabel * nameLabel = (UILabel *) [cell.contentView viewWithTag:NameTag];
Add *theObj = [self.theArray objectAtIndex:indexPath.row - 1];
[nameLabel setText:theObj.itemName];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIImageView *imageView = [cell viewWithTag:kTagCellImageView];
if (imageView == nil) {
imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10.0, 10.0, 13.0, 25.0)];
imageView.backgroundColor = [UIColor clearColor];
imageView.tag = kTagCellImageView;
[cell.contentView addSubview:imageView];
}
if([theObj.itemName isEqualToString:#"First Street"]){
imageView.frame = CGRectMake(14,10,13,25);
[imageView setImage:[UIImage imageNamed:#"firststreet"]];
}
else if([theObj.itemName isEqualToString:#"Second Street"]){
imageView.frame = CGRectMake(8,12,29,20);
[imageView setImage:[UIImage imageNamed:#"second"]];
}
else if([theObj.itemName isEqualToString:#"Main Street"]){
imageView.frame = CGRectMake(15,10,13,25);
[imageView setImage:[UIImage imageNamed:#"mainstreet"]];
}
else{
imageView.frame = CGRectMake(8,8,25,25);
[imageView setImage:[UIImage imageNamed:#"iconcustom"]];
}
NSLog(#"%#",itemName);
NSLog(#"%#",itemCategory);
}
return cell;
}
Also here is my cellForRow:
- (NSInteger)tableView:(UITableView *)popTableView numberOfRowsInSection:(NSInteger)section {
return [self.theArray count] + 1; //Add Extra cell to beginning
}
Any ideas would be greatly appreciated.
You need to use a different reuseIdentifier for your first cell. Try this:
NSString *cellIdentifier;
if (indexPath.row == 0) {
cellIdentifier = #"first";
} else {
cellIdentifier = #"not first";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
// .. cell initialization
}
Obligatory tangential answer - have you thought about setting the tableHeaderView on the UITableView instead? I think that'd accomplish what you're trying to do in a cleaner way (in that it adds an arbitrary view to the top of the table).
Just create a UIView with your "add a new item" controls in it and then set it as the header view when first creating the table.
The issue is here
static NSString *CellIdentifier = #"Cell";
static NSInteger NameTag = 1;
UITableViewCell *cell = [popTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
you are dequeueing all of the cells with the same identifier. Row 1 (index 0) needs to have its own CellIdentifier. Also it looks like you keep adding subviews to the same cells that you dequeue. On your if(cell == nil) check you may want to decide if you want to remove all of the cells contentView subviews or reuse them.
Table view cell management has driving me crazy from past two days. Please check the code below and I will explain you the problem in detail..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *nameLabel,*sugarLabel,*searchNameLabel,*searchSugarLabel;
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
CGFloat width = [UIScreen mainScreen].bounds.size.width - 50;
CGFloat height = 20;
CGRect frame = CGRectMake(10.0f, 10.0f, width, height);
if(isSearchOn)
{
searchNameLabel = [[UILabel alloc] initWithFrame:frame];
searchNameLabel.textColor = [UIColor blackColor];
searchNameLabel.backgroundColor = [UIColor clearColor];
searchNameLabel.textAlignment = UITextAlignmentLeft;
searchNameLabel.font = [UIFont systemFontOfSize:14.0f];
searchNameLabel.tag=260;
[cell.contentView addSubview:searchNameLabel];
[searchNameLabel release];
searchSugarLabel= [[UILabel alloc] initWithFrame:frame];
searchSugarLabel.textColor = [UIColor blackColor];
searchSugarLabel.backgroundColor = [UIColor clearColor];
searchSugarLabel.textAlignment = UITextAlignmentLeft;
searchSugarLabel.font = [UIFont systemFontOfSize:14.0f];
searchSugarLabel.tag=160;
[searchSugarLabel setHidden:YES];
[cell.contentView addSubview:searchSugarLabel];
[searchSugarLabel release];
}
else{
nameLabel = [[UILabel alloc] initWithFrame:frame];
nameLabel.textColor = [UIColor blackColor];
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.textAlignment = UITextAlignmentLeft;
nameLabel.font = [UIFont systemFontOfSize:14.0f];
nameLabel.tag=60;
[cell.contentView addSubview:nameLabel];
[nameLabel release];
sugarLabel= [[UILabel alloc] initWithFrame:frame];
sugarLabel.textColor = [UIColor blackColor];
sugarLabel.backgroundColor = [UIColor clearColor];
sugarLabel.textAlignment = UITextAlignmentLeft;
sugarLabel.font = [UIFont systemFontOfSize:14.0f];
sugarLabel.tag=160;
[sugarLabel setHidden:YES];
[cell.contentView addSubview:sugarLabel];
[sugarLabel release];
}
}
else {
if(isSearchOn)
{
searchNameLabel=(UILabel *)[cell.contentView viewWithTag:260];
searchSugarLabel=(UILabel *)[cell.contentView viewWithTag:160];
}
else{
nameLabel=(UILabel *)[cell.contentView viewWithTag:60];
sugarLabel=(UILabel *)[cell.contentView viewWithTag:160];
}
}
if (isSearchOn) {
cellValue = [searchResult objectAtIndex:indexPath.row];
searchSugarLabel.text=cellValue.sugarId;
NSString *searchText = [NSString stringWithFormat:#"%# %#", cellValue.firstName, cellValue.lastName];
searchNameLabel.text=searchText;
NSLog(#"%#",searchNameLabel.text);
NSLog(#"%#",searchSugarLabel.text);
}
else {
NSString *contact=[contactKeys objectAtIndex:[indexPath section]];
NSArray *contactSection=[contactNames objectForKey:contact];
sugar=[db getSugarId:#"Contacts" bySection:contact andIndex:indexPath.row];
NSString *cellText = [contactSection objectAtIndex:[indexPath row]];
// split the text by the : to get an array containing { "AAA", "BBB" }
NSArray *splitText = [cellText componentsSeparatedByString:#":"];
// form a new string of the form "BBB AAA" by using the individual entries in the array
NSString *contactText = [NSString stringWithFormat:#"%# %#", [splitText objectAtIndex:1], [splitText objectAtIndex:0]];
nameLabel.text = contactText;
sugarLabel.text = sugar;
}
return cell;
}
Contacts is a class which has the properties firstName,lastName and sugar id in it..I am assigning the properties of a contacts class to the variables in the database method and returning an array of contact objects. searchResult is now an array of contact objects.The problem is when I logged the contents on the console the database gets everything in it and returns an array of contacts.The contacts in the searchResult points to different memory locations but when I try to debug the cellForRowAtIndexPath method after it gets 6 contacts..the 7th contact points to the same memory location as the 1st and it repeats thus in the searchNameLabel.text it returns a null and indexPath points to nil...I think it is cell re use issue and I accept that I am very bad in that..I need to figure this out as I am going to finish off my project with this...please guys help me...
This happens only when I try to search for the contacts. It works fine when I try to load all the contacts onto the table..
You are initializing your subviews in the if(cell== nil) block, but in the corresponding else-block, you overwrite them again.
You should rethink your design: Do not load different views by searchon, but set their properties depending on searchon
if(cell == nil){
//do all initializing
}
if(searchon){
//set view/label properties for searching style
} else {
//set view/label properties for not-searching style
}
another approach could be to have totally separated NIB files for the searchon/!searchon
if(searchon){
static NSString *SearchOnCellIdentifier = #"SearchOnCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SearchOnCellIdentifier];
if (cell == nil){
//load cell from extra nib
}
} else {
static NSString *SearchOFFCellIdentifier = #"SearchOFFCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SearchOFFCellIdentifier];
if (cell == nil){
//load cell from extra nib
}
}
NOTE: I never did that and it is not tested.