Placeholders reappear when scrolling uitextField out of view - ios - ios

I have a uiview consisting of a map view on top, and a uitableview below. the table view has cells with uitextFields in them with placeholders.
When I edit the fields the placeholder disappears correctly, but if I scroll the uitableviewcells out of sight (i.e. "behind" the map view that sits above the table view), the placeholders reappear together with the content that was written into the uitextfield.
If I replace the placeholders with normal text, and clear the text on textFieldDidBeginEditing, the same ghosting effect happens. Both the placeholder text and the input shows.
I have tried setting placeholders and text to nil in textFieldDidBeginEditing, but to no avail.
The table view uses michaeltyson's TPKeyboardAvoidingTableView.
edit
Added my cellForRowAtIndex:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"Cell%d", indexPath.row ]];
cell.textLabel.text = _tableData[indexPath.row];
if (indexPath.row == 0) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.placeholder = #"(Required)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 1) {
UILabel *textField = [[UILabel alloc] initWithFrame:CGRectMake(110, 6, 185, 30)];
textField.text = #"(Required)";
textField.textColor = [UIColor lightGrayColor];
textField.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:textField];
secondCellField = textField;
secondCell = cell;
} else if (indexPath.row == 2) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 3) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 4) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 5) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 6) {
UISwitch *textField = [[UISwitch alloc] initWithFrame:CGRectMake(210, 8, 50, 30)];
[textField addTarget:self action:#selector(segwayToWork) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:textField];
_workSwitch = textField;
}
return cell;

Your problem is mutiple TextFields are created for different cell. You need to use reusable cells
Like:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
// allocate the cell:
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
if (indexPath.row == 0) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.tag = 1111;//tag
textField.placeholder = #"(Required)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 1) {
UILabel *textField = [[UILabel alloc] initWithFrame:CGRectMake(110, 6, 185, 30)];
textField.text = #"(Required)";
textField.tag = 1111;//tag
textField.textColor = [UIColor lightGrayColor];
textField.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:textField];
secondCellField = textField;
secondCell = cell;
} else if (indexPath.row == 2) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.tag = 1111;//tag
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 3) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.tag = 1111;//tag
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 4) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.tag = 1111;//tag
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 5) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.tag = 1111;//tag
textField.delegate = self;
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} elseif (indexPath.row == 6) {
UISwitch *textField = [[UISwitch alloc] initWithFrame:CGRectMake(210, 8, 50, 30)];
textField.tag = 1111;//tag
[textField addTarget:self action:#selector(segwayToWork) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:textField];
_workSwitch = textField;
}
}
cell.textLabel.text = _tableData[indexPath.row];
return cell;
}
I have tryied to reuse UITableViewCell So please customize it as per your requirement. you can use this code also.

Creating new text fields is indeed the problem. You should NOT alloc/init any text fields in cellForRowAtIndexPath.
Instead, either make a custom cell or use the "dynamic prototype" in your storyboard file. Give your text field a tag so you can easily configure it.
//above
#define TextFieldTag 42
// in cellForRowAtIndexPath:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
// If #"Cell" is the identifier you specified
// if you have storyboard or a xib, no need to check for cell==nil
UITextField *textField = (UITextField*) [cell viewWithTag:TextFieldTag];
// configure the text field based on indexPath.row
In case you are not using storyboard or xibs, you can lazily instantiate the text field like this:
UITextField *textField = (UITextField*) [cell viewWithTag:TextFieldTag];
if (!textField) {
textField = [[UITextField alloc] initWithFrame:textFieldFrame];
textField.tag = TextFieldTag;
// more standard configuration
[cell.contentView addSubview:textField];
}
And by the way, here is another tip for you. You should not hard code your table view rows. This results in not very readable code. You can use a simple enum on top of your class:
typedef enum {
NameCell, AddressCell,
FirstOptionalCell, SecondOptionalCell,
ThirdOptionalCell, CellCount } TableCell;
You can then just return "CellCount" in numberOrRowsInSection and reference the rows like this:
if (indexPath.row == NameCell)

The problem here is that everytime a cell gets reloaded, you initialize a new text view which won't have the text that was previously entered. The best solution to this problem is for you to keep an NSMutableArray* that stores the user's input. You have different options, i'll just describe the steps for one possible solution:
declare an NSMutableArray property for storing the user inputs as follows:
#property (strong, nonatomic) NSMutableArray *userData;
and the getter that performs lazy initialisation:
-(NSMutableArray *)userData
{
if(!_userData){
_userData = [[NSMutableArray alloc] initWithCapacity:[self.tableData count]];
for (int i = 0; i < [self.tableData count]; i++)
[_userData addObject:#""];
}
return _userData;
}
Use the textfield's property tag to store the row for the particular textfield as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"Cell%d", indexPath.row ]];
if(cell == nil)
cell = [[UITableViewCell alloc] init];
cell.textLabel.text = _tableData[indexPath.row];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.delegate = self;
textField.tag = indexPath.row;
if (indexPath.row == 0) {
textField.placeholder = #"(Required)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 1) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(110, 6, 185, 30)];
label.text = #"(Required)";
label.textColor = [UIColor lightGrayColor];
label.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:label];
secondCellField = label;
secondCell = cell;
} else if (indexPath.row == 2) {
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 3) {
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 4) {
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 5) {
textField.placeholder = #"(Optional)";
[cell.contentView addSubview:textField];
} else if (indexPath.row == 6) {
UISwitch *switch = [[UISwitch alloc] initWithFrame:CGRectMake(210, 8, 50, 30)];
[switch addTarget:self action:#selector(segwayToWork) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:switch];
_workSwitch = switch;
}
if(![[self.userData objectAtIndex:indexPath.row] isEqualToString:#""]){
NSLog(#"%# at indexPath.row %d",[self.userData objectAtIndex:indexPath.row], indexPath.row);
textField.placeholder = nil;
textField.text = [self.userData objectAtIndex:indexPath.row];
}
return cell;
}
Finally, in your UITextField delegate, you can do something like:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
self.userData[textField.tag] = textField.text;
return YES;
}
Now when a cell will be reloaded, it will first check whether there was already a user input, and if there was one, it will set the placeholder to nil and will instead show just the user input.

Related

No access to UILabel

I am setting an UILabel inside of the cellForRowAtIndexPath method and when the user changes the text, the label should change. But even it is not nil, it doesn't change.
#property UILabel *myLabel;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, textView.frame.size.width, 37)];
self.myLabel.text = #"Old Text";
}
- (void)textViewDidChange:(UITextView *)textView {
self.myLabel.textColor = [UIColor redColor];
self.myLabel.text = #"New Text";
}
I found a solution where some people are changing the UILabel in the main thread but that's not working for me.
dispatch_async(dispatch_get_main_queue(), ^{
// Do in main thread
});
If you want to modify the label of a cell that's on-screen "on the fly" then you need a way to reach the label.
What I usually do is to create a template for the cell in IB, define a custom subclass of UITableViewCell, and set the cell's class to that custom subclass. Then I connect outlets between the cell and all the custom fields I've created.
In my cellForRowAtIndexPath method, I dequeue a cell and cast it to my custom type. Then I reference the fields in the cell through the cell, e.g.
cell.myLabel.
If you add a new field to your cell in cellForRowAtIndexPath you have a couple of problems. First, you need to make sure you don't add another copy of that new field when you recycle the cell. Second, you need a way to get to the field if you want to modify it, as in your question. There are ways to deal with these problems, but the approach I outlined above is cleaner.
Duncan, I'm sorry, here is the rest of the cellForRowAtIndexPath. I thought it could not be a problem of reusing the cell as I'm not scrolling so the cell should not be recreated.
#property NSString *textField_1;
#property NSString *textField_2;
// ...
#property UILabel *myLabel;
#end
#implementation TableViewController
- (void)textViewDidChange:(UITextView *)textView
{
self.myLabel.textColor = [UIColor redColor];
self.myLabel.text = #"New Text";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if(indexPath.section == 0)
{
float displayResolutionWidth = self.view.frame.size.width;
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, displayResolutionWidth - 165, 50)];
textField.delegate = self;
textField.tag = indexPath.row;
textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(0, 0, displayResolutionWidth - 90, 176)];
textView.delegate = self;
textView.tag = indexPath.row;
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, textView.frame.size.width, 37)];
self.myLabel.textColor = [UIColor redColor];
if(indexPath.row == 17)
{
cell.accessoryView = textView;
[textView addSubview:self.myLabel];
}
else if (indexPath.row != 17)
{
cell.accessoryView = textField;
}
if (self.object)
{
if (indexPath.row == 0)
textField.text = self.object.property_1;
if (indexPath.row == 1)
textField.text = self.object.property_2;
}
else if (!self.object)
{
if (indexPath.row == 0)
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:NSLocalizedString(#"Placeholder_1", #"")
attributes:#{NSForegroundColorAttributeName: [UIColor greenColor]}];
if (indexPath.row == 1)
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:NSLocalizedString(#"Placeholder_2", #"")
attributes:#{NSForegroundColorAttributeName: [UIColor greenColor]}];
if (indexPath.row == 17)
self.myLabel.text = "Old Text";
}
if (indexPath.row != 17)
{
cell.textLabel.text = [self.arrayWithObjectData objectAtIndex:indexPath.row];
}
else if (indexPath.row == 17)
{
UILabel *mylabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 0, 150, 40)];
mylabel.text = self.arrayWithObjectData[17];
mylabel.textColor = [UIColor COLOR_TEXT];
[cell.contentView addSubview:mylabel];
}
}
return cell;
}
#end

How to show different labels in different sections?

I want to set labels in section... How can i set different labels in different section cz in tableview i want to make different sections and i am using the title for header in section.. by doing this i make different sections correctly but not able to differentiate the data between the sections.. Anyone can help me
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
// create the parent view that will hold header Label
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0,-60,300,60)];
// create the label object
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.frame = CGRectMake(0,0,self.view.frame.size.width,60);
UIColor* mainColor = [UIColor colorWithRed:47.0/255 green:168.0/255 blue:228.0/255 alpha:1.0f];
headerLabel.backgroundColor = mainColor;
headerLabel.font = [UIFont boldSystemFontOfSize:18];
headerLabel.textAlignment = UITextAlignmentCenter;
//
// UILabel *firstSection = [[UILabel alloc] initWithFrame:CGRectZero];
// firstSection.frame = CGRectMake(0,0,self.view.frame.size.width,60);
//
// firstSection.font = [UIFont boldSystemFontOfSize:18];
UIView *firstSection = [[UIView alloc] initWithFrame:CGRectMake(0,-60,300,60)];
//headerLabel.textAlignment = UITextAlignmentCenter;
if(section == 0)
headerLabel.text = #"Reciever Party";
UILabel *nameLbl =[[UILabel alloc]initWithFrame:CGRectMake(20, 35, 100 ,50)];
nameLbl.text =#"Name";
nameLbl.textColor=[UIColor blackColor];
UIFont *bold = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
[nameLbl setFont:bold];
nameLbl.backgroundColor =[UIColor clearColor];
[headerLabel addSubview:nameLbl];
UILabel *addLbl =[[UILabel alloc]initWithFrame:CGRectMake(20, 65, 100 ,50)];
addLbl.text =#"Address";
addLbl.textColor=[UIColor blackColor];
UIFont *bold1 = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
[addLbl setFont:bold1];
addLbl.backgroundColor =[UIColor clearColor];
[headerLabel addSubview:addLbl];
if(section == 1)
headerLabel.text = #"Sender Party";
UILabel *senderName =[[UILabel alloc]initWithFrame:CGRectMake(20, 125, 100 ,50)];
senderName.text =#"Address";
senderName.textColor=[UIColor blackColor];
UIFont *bold2 = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
[addLbl setFont:bold2];
senderName.backgroundColor =[UIColor clearColor];
[headerLabel addSubview:senderName];
if(section == 2)
headerLabel.text = #"Third Section Header";
headerLabel.textColor = [UIColor whiteColor];
[customView addSubview:headerLabel];
return customView;
}
I am giving you a sample with hard coded data that how can you show data in section tableView. viewForHeaderInSection is responsible for creating headers of each section, not for showing data in section's row.
I am adding label on cell's content view as you don't want to add this from storyboard/ prototype cell.
Try this:-
In cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"YourIdentifier"];
/*
* If the cell is nil it means no cell was available for reuse and that we should
* create a new one.
*/
if (cell == nil) {
/*
* Actually create a new cell (with an identifier so that it can be dequeued).
*/
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"YourIdentifier"];
UILabel *lbl =[[UILabel alloc]initWithFrame:CGRectMake(20, 15, 100 ,50)];
lbl.textColor=[UIColor blackColor];
UIFont *bold1 = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
[lbl setFont:bold1];
lbl.hidden = NO;
lbl.tag = 101;
lbl.backgroundColor =[UIColor clearColor];
[cell.contentView addSubview:lbl];
}
UILabel *lblCell = (UILabel*)[cell.contentView viewWithTag:101];
if(indexPath.section == 0) //first section
{
if (indexPath.row == 0) //first row of first section
{
lblCell.text =#"Name";
}
if (indexPath.row == 1) //second row of first section
{
lblCell.text =#"Address";
}
}
if(indexPath.section == 1) //second section
{
if (indexPath.row == 0) //first row of second section
{
lblCell.text =#"age";
}
if (indexPath.row == 1) //second row of second section
{
lblCell.text =#"phone no.";
}
}
if(indexPath.section == 2) //third section
{
if (indexPath.row == 0) //first row of third section
{
lblCell.text =#"city";
}
if (indexPath.row == 1) //second row of third section
{
lblCell.text =#"father";
}
}
/* Now that the cell is configured we return it to the table view so that it can display it */
return cell;
}
you have to use like that
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 40;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
UIView *sectionView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 225, 40)];
UIImageView *sectionImage = [[UIImageView alloc]initWithFrame:CGRectMake(5, 0, 40, 40)];
sectionImage.image = [UIImage imageNamed:[objMenuImageList objectAtIndex:section]];
sectionImage.contentMode = UIViewContentModeCenter;
[sectionView addSubview:sectionImage];
UILabel *sectionLable = [[UILabel alloc]initWithFrame:CGRectMake(50, 10, 150, 20)];
sectionLable.contentMode = UIViewContentModeLeft;
sectionLable.text = [objMenuList objectAtIndex:section];
[sectionLable setFont:[UIFont systemFontOfSize:14]];
sectionLable.textColor = [UIColor colorWithRed:(206/255.f) green:(180/255.f) blue:(116/255.f) alpha:1.0f];
[sectionView addSubview:sectionLable];
UIButton *sectionButton = [UIButton buttonWithType:UIButtonTypeCustom];
sectionButton.frame = CGRectMake(0, 0, sectionView.frame.size.width, sectionView.frame.size.height -10);
sectionButton.center = sectionView.center;
sectionButton.tag = section;
// sectionButton.backgroundColor = [UIColor yellowColor];
[sectionButton addTarget:self action:#selector(ExpandCell:) forControlEvents:UIControlEventTouchUpInside];
[sectionView addSubview:sectionButton];
sectionView.backgroundColor = [UIColor clearColor];
return sectionView;
}
Just keep It simple And Flexible.
Do it like this..
Step 1. Add one custom cell For Header View with UILabel for title.
Step 2. In cellForRowAtIndexPath , dequeueReusableCellWithIdentifier this cell .
Use condition as...
` if(section==0){
Cell.title.text= #"your title for section 0"
} // here title is UILabel `
By doing this your code is Flexible enough for Any Future Changes!!!

how to disable a super view while clicking a button on subview in iOS

Here I have a button in UITableViewCell. If I click button the another view should popup. If I click the same button then the view should be disable. Please help me out from this. Thanks in advance.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellIdentifier"];
cell.frame = CGRectZero;
cell.backgroundColor = [UIColor whiteColor];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(20, 0, 250, 50)];
label.font = [UIFont lightFontWithSize:14];
label.textAlignment = NSTextAlignmentLeft;
label.textColor = [UIColor blackColor];
label.highlightedTextColor = [UIColor whiteColor];
label.numberOfLines = 2;
label.tag = 1;
ForumDBFilePath* currObj = [forumResultArray objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#",currObj.postcontent];
cell.textLabel.font = [UIFont regularFontWithSize:15];
[cell.contentView addSubview:label];
UIBackgroundButton* replyButton = [UIBackgroundButton buttonWithType:UIButtonTypeCustom];
[replyButton setButtonColor:[UIColor whiteColor] setBackgroundColor:[UIColor getNavBarColor]];
[replyButton setTitle:#"Reply" forState:UIControlStateNormal];
replyButton.tag = indexPath.row;
[replyButton.titleLabel setFont:[UIFont mediumFontWithSize:14]];
[replyButton setFrame:CGRectMake(viewWidth-0, 15, 125, 30)];
[replyButton addTarget:self action:#selector(replyButton:) forControlEvents:UIControlEventTouchUpInside];
[replyButton resignFirstResponder];
[cell.contentView addSubview:replyButton];
}
return cell;
}
You can override superview method like this:
- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
id hitView = [super hitTest:point withEvent:event];
if (hitView == self) {
return nil;
} else {
return hitView;
}
}
Hope it helps you.

UItableView Cell Resuablity Data getting interchaged while scrolling

Hi All,
- (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(10, 5, 200, 30)];
textField.tag = 123;
textField.placeholder = #"Enter Text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.delegate = self;
[cell.contentView addSubview:textField];
}
UITextField *textField = (UITextField *) [cell.contentView viewWithTag:123];
if (indexPath.row == 0) {
[textField setPlaceholder:#"Employee ID"];
}
else if (indexPath.row == 1)
{
[textField setPlaceholder:#"Employee Name"];
}
else if (indexPath.row == 2)
{
[textField setPlaceholder:#"Employee Phone"];
}
if (indexPath.row == 3)
{
[textField setPlaceholder:#"Employee Email"];
UIButton *saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[saveButton setFrame:CGRectMake(200, 0, 100, 40)];
[saveButton setTitle:#"Save Emp" forState:UIControlStateNormal];
[saveButton addTarget:self action:#selector(saveEmployeeToCoreData:) forControlEvents:UIControlEventTouchUpInside];
[saveButton setTag:indexPath.section];
[cell addSubview:saveButton];
}
return cell;
}
Hi Everyone,
I am using this piece of code for getting the above output
But when i am scrolling the tableview the output i am getting is
And if i enter any text in the section and scrolling the text, then the text is changing in the cells.
You are adding a subview to the cell in one of the cases:
[cell addSubview:saveButton];
This subview does NOT get removed when you dequeue an old cell. You have to explicitly remove the subview for those cases. This will cause unexpected behaviour.
I really recommend to subclass UITableViewCell and add the components to that subclass. by doing so, you can hide its saveButton-property for the cases where you do not want a saveButton.
Initialize your UITextField and UIButton with tag in
if (cell == nil)
{
//Initialize your `UITextField` and `UIButton`
// also set tag
}
And set frame of UITextField and UIButton at out of if statement. (you can get UITextField and UIButton by its tag)
sure its working for you.
I too had the same problem,try this,
UITableViewCell *cell;
if (cell == nil) {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//initialize the tableviewcell outside,
You need to use the custom UITableViewCell & in that class file, you need to get this tied up in the cell Class file . More importantly, need to maintain the datasource for it .
Don't use the tag as 0. I mean, set something similar for every views
txtView.tag = 25+indexPath.section;
Change this "textField.tag = 123" to "text.tag = indexPath.row" in all places. It will work properly.
In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (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(10, 5, 200, 30)];
textField.tag = 123;
textField.placeholder = #"Enter Text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.delegate = self;
[cell.contentView addSubview:textField];
} else {
//here the cell is reused, so remove the button here
[[cell.contentView viewWithTag:124] removeFromSuperview];
}
UITextField *textField = (UITextField *) [cell.contentView viewWithTag:123];
if (indexPath.row == 0) {
[textField setPlaceholder:#"Employee ID"];
}
else if (indexPath.row == 1)
{
[textField setPlaceholder:#"Employee Name"];
}
else if (indexPath.row == 2)
{
[textField setPlaceholder:#"Employee Phone"];
}
if (indexPath.row == 3)
{
[textField setPlaceholder:#"Employee Email"];
UIButton *saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[saveButton setFrame:CGRectMake(200, 0, 100, 40)];
[saveButton setTag:124];
[saveButton setTitle:#"Save Emp" forState:UIControlStateNormal];
[saveButton addTarget:self action:#selector(saveEmployeeToCoreData:) forControlEvents:UIControlEventTouchUpInside];
//[saveButton setTag:indexPath.section];
[cell.contentView addSubview:saveButton];
}
return cell;
}
As per your screen shot there are three visible cell. so when ever you load 4th cell ios will give you reference of 1st cell. here you have already set button for employee email. so that it will visible and again you also set employee id and phone.
So when you reuse the cell your logic should like you need to reset the cell to the default case in this example you can remove that button or hide it and then as per the cell info you should set the cell properties.
I hope you understand the problem.
if (indexPath.row == 3)
{
[textField setPlaceholder:#"Employee Email"];
UIButton *saveButton = [cell.contentView viewWithTag:124];
if(saveButton == nil)
saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[saveButton setFrame:CGRectMake(200, 0, 100, 40)];
[saveButton setTag:124];
[saveButton setTitle:#"Save Emp" forState:UIControlStateNormal];
[saveButton addTarget:self action:#selector(saveEmployeeToCoreData:) forControlEvents:UIControlEventTouchUpInside];
//[saveButton setTag:indexPath.section];
[cell.contentView addSubview:saveButton];
}
Try this code it reuse cells in table view
- (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(10, 5, 200, 30)];
textField.tag = 123;
textField.placeholder = #"Enter Text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.delegate = self;
[cell.contentView addSubview:textField];
UIButton *saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[saveButton setFrame:CGRectMake(200, 0, 100, 40)];
[saveButton setTitle:#"Save Emp" forState:UIControlStateNormal];
[saveButton addTarget:self action:#selector(saveEmployeeToCoreData:) forControlEvents:UIControlEventTouchUpInside];
[saveButton setTag:124];
[cell.contentView addSubview:saveButton];
}
UITextField *textField = (UITextField *) [cell.contentView viewWithTag:123];
UIButton *saveButton =(UIButton*)[cell.contentView viewWithTag:124];
saveButton.hidden=YES;
if (indexPath.row == 0) {
[textField setPlaceholder:#"Employee ID"];
}
else if (indexPath.row == 1)
{
[textField setPlaceholder:#"Employee Name"];
}
else if (indexPath.row == 2)
{
[textField setPlaceholder:#"Employee Phone"];
}
if (indexPath.row == 3)
{
[textField setPlaceholder:#"Employee Email"];
saveButton.hidden=NO;
}
return cell;
}

ios - adding text fields to uitableviewcell programmatically not working

Rookie ios question. I am trying to create a sign up form using a table view controller. I am trying add textfields to each cell programmatically in the cellForRowAtIndexPath method but all my text fields seem to getting created on the first cell - one overlapping the other. Here is my code.
Here is how my cells are rendering. I think I am doing something goofy with the part that is reusing the cells. I did check some some other similar threads on stackoverflow but none of them helped. Could you please tell me what i am missing or is this even the way this is supposed to be done. Your inputs are really appreciated.
Thanks,
Mike
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"signUpFields" forIndexPath:indexPath];
// Configure the cell...
if (indexPath.row == 0){
//self.firstName = [[UITextField alloc] initWithFrame:CGRectMake(5, 0, 280, 21)];
self.firstName = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.firstName.placeholder = #"First Name";
self.firstName.autocorrectionType = UITextAutocorrectionTypeNo;
[self.firstName setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.firstName;
[cell.contentView addSubview:self.firstName];
}
if (indexPath.row == 1){
self.lastName = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.lastName.placeholder = #"Last Name";
self.lastName.autocorrectionType = UITextAutocorrectionTypeNo;
[self.lastName setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.lastName;
[cell.contentView addSubview:self.lastName];
}
if (indexPath.row == 2){
self.emailId = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.emailId.placeholder = #"Email Id";
self.emailId.autocorrectionType = UITextAutocorrectionTypeNo;
[self.emailId setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.emailId;
[cell.contentView addSubview:self.emailId];
}
if (indexPath.row == 3){
self.password = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.password.placeholder = #"Password";
self.password.secureTextEntry = YES;
self.password.autocorrectionType = UITextAutocorrectionTypeNo;
[self.password setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.password;
[cell.contentView addSubview:self.password];
}
self.firstName.delegate = self;
self.lastName.delegate = self;
self.emailId.delegate = self;
self.password.delegate = self;
[self.signUpTable addSubview:self.firstName];
[self.signUpTable addSubview:self.lastName];
[self.signUpTable addSubview:self.emailId];
[self.signUpTable addSubview:self.password];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Try 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];
}
if (indexPath.row == 0){
//self.firstName = [[UITextField alloc] initWithFrame:CGRectMake(5, 0, 280, 21)];
self.firstName = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.firstName.placeholder = #"First Name";
self.firstName.autocorrectionType = UITextAutocorrectionTypeNo;
[self.firstName setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.firstName;
[cell addSubview:self.firstName];
}
if (indexPath.row == 1){
self.lastName = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.lastName.placeholder = #"Last Name";
self.lastName.autocorrectionType = UITextAutocorrectionTypeNo;
[self.lastName setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.lastName;
[cell addSubview:self.lastName];
}
if (indexPath.row == 2){
self.emailId = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.emailId.placeholder = #"Email Id";
self.emailId.autocorrectionType = UITextAutocorrectionTypeNo;
[self.emailId setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.emailId;
[cell addSubview:self.emailId];
}
if (indexPath.row == 3){
self.password = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.password.placeholder = #"Password";
self.password.secureTextEntry = YES;
self.password.autocorrectionType = UITextAutocorrectionTypeNo;
[self.password setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.password;
[cell addSubview:self.password];
}
self.firstName.delegate = self;
self.lastName.delegate = self;
self.emailId.delegate = self;
self.password.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
no need to add again text view in table view, this is wrong. Try this, this will work for you but better you should create a custom Cell and use. That is the best way to do it, because you can use whatever you want with Cell.
Don't add them as subviews, set them as the cell's accessory view.
- (UITextField*)getTextField{
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 20, 35)];
tf.delegate = self;
tf.textColor = [UIColor colorWithRed:.231 green:.337 blue:.533 alpha:1];
tf.autocorrectionType = UITextAutocorrectionTypeNo;
tf.borderStyle = UITextBorderStyleNone;
tf.frame = CGRectMake(0, 20, 170, 30);
tf.clearButtonMode = UITextFieldViewModeWhileEditing;
tf.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
tf.font = [UIFont systemFontOfSize:13];
return tf;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
cell.textLabel.font = [UIFont systemFontOfSize:13];
cell.detailTextLabel.font = [UIFont systemFontOfSize:13];
cell.detailTextLabel.numberOfLines = 2;
}
if (indexPath.section == 0) {
UITextField *tf = (UITextField*)cell.accessoryView;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.numberOfLines = 2;
tf = [self getTextField];
cell.accessoryView = cell.editingAccessoryView = tf;
[((UITextField*)cell.accessoryView) setBorderStyle:self.tableView.editing ? UITextBorderStyleRoundedRect : UITextBorderStyleNone];
[((UITextField*)cell.accessoryView) setUserInteractionEnabled:self.tableView.editing ? YES : NO];
[((UITextField*)cell.accessoryView) setTextAlignment:!self.tableView.editing ? UITextAlignmentRight : UITextAlignmentLeft];
((UITextField*)cell.accessoryView).tag = indexPath.row;
}
return cell;
}
The idea is that the cell is re-drawn each time it appears on screen, coming from off the screen and if you add the text field with addSubview:, it will add it each time as well. You COULD do it, but then you have to clear the cell's contentView of subviews, but that requires extra work, cpu and memory use, and not to say it's the least elegant solution.
Looks like you have just four cells you want to display. This is a static case, the cells don't change, you should create this tableView and its cells statically in the xib/storyboard. That is the preferred way here.
If you really want to do it programmatically, create four UITableViewCells with the behavior you want before hand. Keep them in an array. Inside cellForRowAtIndex path return cellArray[indexPath.row];
Note this is the best approach only because you have just four tableViewCells.
ReuseIdentifiers come in handy only if you have more cells than can be accommodated on the screen at once. So in your case, you never actually reuse the cells.
keep this one and try it,
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *MyIdentifier = [NSString stringWithFormat:#"%d%d",indexPath.row,indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
//your stuff.
}
}
Try to use this one ...And there is no need to add these textfield to tableview. So please remove some code..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"signUpFields" forIndexPath:indexPath];
// Configure the cell...
if (indexPath.row == 0){
//self.firstName = [[UITextField alloc] initWithFrame:CGRectMake(5, 0, 280, 21)];
self.firstName = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.firstName.placeholder = #"First Name";
self.firstName.autocorrectionType = UITextAutocorrectionTypeNo;
[self.firstName setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.firstName;
[cell addSubview:self.firstName];
}
if (indexPath.row == 1){
self.lastName = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.lastName.placeholder = #"Last Name";
self.lastName.autocorrectionType = UITextAutocorrectionTypeNo;
[self.lastName setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.lastName;
[cell addSubview:self.lastName];
}
if (indexPath.row == 2){
self.emailId = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.emailId.placeholder = #"Email Id";
self.emailId.autocorrectionType = UITextAutocorrectionTypeNo;
[self.emailId setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.emailId;
[cell addSubview:self.emailId];
}
if (indexPath.row == 3){
self.password = [[UITextField alloc] initWithFrame:CGRectMake(120, 13, 375, 30)];
self.password.placeholder = #"Password";
self.password.secureTextEntry = YES;
self.password.autocorrectionType = UITextAutocorrectionTypeNo;
[self.password setClearButtonMode:UITextFieldViewModeWhileEditing];
//cell.accessoryView = self.password;
[cell addSubview:self.password];
}
self.firstName.delegate = self;
self.lastName.delegate = self;
self.emailId.delegate = self;
self.password.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Instead of writing more cells just create one custom cell with textfield.Give the tag for each textfield and also set the count of rows in numberOfRowsIntheSections then it will display the cells how much you need. I think it will helps you.
Before You follow my Answer i wnat to tell you that following code is bad for memory management because it will create new cell for each rows of UITableView, so be careful for it.
But it is better to use, When UITableView Have Limited rows (about 50-100 may be ) then following code is helpful in your case, use it, If it is suitable for you.
- (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] autorelease];
/// Put/Create your UITextField or any Controls here
}
return cell;
}
#Mike : First of all I will suggest you to go with StoryBoard or Nib files.
If you use this, then you can use following code
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField = (UITextField *)[cell viewWithTag:1];
txtField.text = #"Latest";
return cell;
}
Based on row number you can set text.
If you want to add the UITextField at run time. then you can use following code.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField = [[UITextField alloc] initWithFrame:CGRectMake(165.0, 7.0, 150.0, 30.0)];
txtField.text = #"Latest";
[cell.contentView addSubview:txtField];
return cell;
}
You can assign different tag and based on tags you can store those values.

Resources