I have created iOS new app. UITextField is added in each row of UITableView. first row UITextField enter values then add new row the first row UITextField values show in second row UITextField. how to solve this issues. please help me . thanks in advance.
Here is my sample code add row functionality
- (IBAction)btnAddRow:(id)sender {
[self loadData:[self.dataArray count]];
[self.tblview reloadData];
}
-(void ) loadData:(NSInteger) Indexvalue
{
newSheet = [NSDictionary dictionaryWithObjectsAndKeys:strEntryID,entryID, nil];
[self.dataArray insertObject:newSheet atIndex:Indexvalue];
}
- (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 *txtComment = [[UITextField alloc] initWithFrame:CGRectMake(225.0f,5.0f,50.0f,20.0f)];
[txtComment setBorderStyle:UITextBorderStyleLine];
[cell addSubview:txtComment];
[txtComment setTag:indexPath.row];
[txtComment addTarget:self action:#selector(txtCommentChange:) forControlEvents:UIControlEventEditingChanged];
return cell;
}
- (IBAction)btnAddRow:(id)sender {
[self loadData:[self.dataArray count]];
[self.tblview reloadData];
}
-(void ) loadData:(NSInteger) Indexvalue
{
newSheet = [NSDictionary dictionaryWithObjectsAndKeys:strEntryID,entryID, nil];
[self.dataArray insertObject:newSheet atIndex:Indexvalue];
}
- (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];
}
for (UIView *view in cell.subviews) {
if ([view isKindOfClass:[UITextField class]]) {
[view removeFromSuperview];
}
}
UITextField *txtComment = [[UITextField alloc] initWithFrame:CGRectMake(225.0f,5.0f,50.0f,20.0f)];
[txtComment setBorderStyle:UITextBorderStyleLine];
[cell addSubview:txtComment];
[txtComment setTag:indexPath.row];
[txtComment addTarget:self action:#selector(txtCommentChange:) forControlEvents:UIControlEventEditingChanged];
return cell;
}
You write just one for loop after your cell allocation.
txtComment.text = yourText
You missed it
You are adding a new UITextField every time that cellForRowAtIndexPath is called. Cells are re-used as you scroll, so imagine that as a cell goes off the top of the screen, its quickly taken and put at the bottom of the screen to be the new cell that is appearing. This also means that if you added a textfield first time round, then a second one will be added on top of the first.
If you add your UITextField within the same if statement where you initialize your cell, this will prevent more than one textfield appearing. Eg :
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UITextField *txtComment = [[UITextField alloc] initWithFrame:CGRectMake(225.0f,5.0f,50.0f,20.0f)];
[txtComment setBorderStyle:UITextBorderStyleLine];
[cell addSubview:txtComment];
[txtComment setTag:indexPath.row];
[txtComment addTarget:self action:#selector(txtCommentChange:) forControlEvents:UIControlEventEditingChanged];
}
Theres also a method you can use that is called when a cell is about to be recycled : -prepareForReuse. This is called on the UITableViewCell itself though, so you would need a subclass of UITableViewCell to access it.
- (void) prepareForReuse {
//set text fields to #"" for eg
}
Related
I have a UITextField in a custom cell. Once I entered the value in first and second cells and when I scroll the UITableView textfield index are changing (first cell value changing to last cell). Can any one help me to resolve my issue?
Here is my code:
static NSString *cellIdentifier = #"TableCellID";
CustomTableViewCell *cell = (CustomTableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] init]; // or your custom initialization
}
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.txt_TCelltext.tag=indexPath.row;
cell.txt_TCelltext.placeholder=#"0.00";
[cell.txt_TCelltext setDelegate:self];
It is because of cell reuse. Try to populate the UITextField data from a dictionary (or) array. Try this:
- (UITableViewCell *)tableView:(UITableView *)tableViewLocal
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Your Code
UITextField *textField = [[UITextField alloc]init];
textField.delegate = self;
textField.tag = indexPath.row;
if ([myTextFieldDictionary objectForKey:[NSString stringWithFormat:#"%ld", (long)textField.tag]])
{
textField.text = [[myTextFieldDictionary objectForKey:[NSString stringWithFormat:#"%ld", (long)textField.tag]];
}
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[myTextFieldDictionary setValue:textField.text
forKey:[NSString stringWithFormat:#"%ld", (long)textField.tag]];
}
You can write below code in Viewdidload and cell for row at index path.
arrCells = [NSMutableArray new];
for (int i = 0; i < [[dic_demo objectForKey:#"Demo"] count]; i++) {
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
CustomTableViewCell *cell = [objects objectAtIndex:0];
[arrCells addObject:cell];
}-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomTableViewCell *cell = [arrCells objectAtIndex:indexPath.row];
}
Hope this will help you
static NSString *cellIdentifier = #"TableCellID";
in place of this line
use NSString *cellIdentifier = [NSString stringWithFormat:#"Cell_%d_%d", indexPath.section, indexPath.row];
If the cell is newly created, you assign a placeholder/ text to text filed. But if the same cell is reused and incase for the reused cell you didn't assign the placeholder/ text to the textfield from the data source of the current index path than the text filed will show the data for previous index path at which the cell was newly created. So to resolve your issue you need to assign the text to the text field based on the text for the current index path irrespective of the cell is newly created or reused.
To resolve this issue you have two options-
1) update the content of reusable cells text field with the data of the text field for current index path
2) in case of reusable cell release previous text field and create a new one, initialize with the data for the present row.
The 2nd approach involves some overhead, so I would suggest you to resolve your issue with 1st approach.
Sample code using 1st approach-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.backgroundColor=[UIColor clearColor];
UITextField *textField = nil;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"cell"];
}
// assign placeholder text to text field
[cell.textFiled setPlaceholder:[textFiledTextsArray objectAtIndex:indexPath.row]];
return cell;
}
Sample code using 2nd approach-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.backgroundColor=[UIColor clearColor];
UITextField *textField = nil;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"cell"];
}
textField = [[cell contentView] viewWithTag:indexPath.row];
if(textField ! = nil)
[textField removeFRomSuperView];
textField = [[UITextField alloc] initWithFrame:CGRectZero];
// customize text filed
// assign placeholder text to text field
[textFiled setPlaceholder:[textFiledTextsArray objectAtIndex:indexPath.row]];
[textField setTag:indexPath.row]; // set tag on text field
[[cell contentView] addSubview:textField];
[textField release];
return cell;
}
Note: The above sample code is just a rough idea, please use the above source/ customize it as per your requirements.
Place a breakPoint in the function below and you can see it gets called each time a cell becomes visible and hence your code inside that function resets the text in the textField. If something has struck you, don't wait! you can solve it with your own code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I want to add some buttons to custom cell, when I click the button and other buttons also change. How can I click a button without changing the other buttons?
enter code here
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"cell";
SViewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[SViewTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier];
}
cell.cellButton.tag = indexPath.row;
[cell.cellButton addTarget:self action:#selector(clickMe:)
forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (void)clickMe:(UIButton *)sender
{
SViewTableViewCell *cell = (SViewTableViewCell *)[[sender superview]superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if (sender.tag == 0) {
if ([sender.titleLabel.text isEqualToString:openStr]) {
[sender setTitle:closeStr forState:UIControlStateNormal];
}
else{
[sender setTitle:openStr forState:UIControlStateNormal];
}
}
}
I think it's a issue about tableView cell reuse again, you should set the button title in cellForRow to keep reuse cell have a correct title, you should try code like this:
openDict is a NSMutableArray you should define, and this just a example.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"cell";
SViewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[SViewTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier];
[cell.cellButton addTarget:self action:#selector(clickMe:)
forControlEvents:UIControlEventTouchUpInside];
}
NSString *key = [NSString stringWithFormat:#"%d-%d", indexPath.row, indexPath.section];
if (openDict[key] && [openDict[key] boolValue]) {
[sender setTitle:openStr forState:UIControlStateNormal];
}
else{
[sender setTitle:closeStr forState:UIControlStateNormal];
}
cell.cellButton.tag = indexPath.row;
return cell;
}
- (void)clickMe:(UIButton *)sender
{
SViewTableViewCell *cell = (SViewTableViewCell *)[[sender superview]superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if (sender.tag == 0) {
NSString *key = [NSString stringWithFormat:#"%d-%d", indexPath.row, indexPath.section];
if (openDict[key] && [openDict[key] boolValue]) {
openDict[key] = #(0);
[sender setTitle:closeStr forState:UIControlStateNormal];
}
else{
openDict[key] = #(1);
[sender setTitle:openStr forState:UIControlStateNormal];
}
}
}
Please set tag for each button in custom tableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"cell";
SViewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[SViewTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier];
}
UIButton *button1 = (UIButton *)[cell viewWithTag:1];
UIButton *button2 = (UIButton *)[cell viewWithTag:2];
[button1 addTarget:self action:#selector(clickMe:)
forControlEvents:UIControlEventTouchUpInside];
[button2 addTarget:self action:#selector(clickMe:)
forControlEvents:UIControlEventTouchUpInside];
return cell;
}
To add a button to a UITableViewCell you should do it at the time you configure the cell in cellForRowAtIndexPath - this is after you get the cell to reuse. If you want to add a button to a small number of cells you should cause that cell to be reloaded using UITableView's – reloadRowsAtIndexPaths:withRowAnimation: method or reloadData to give you the opportunity to reload all cells.
Any subview you add to a cell should be added to the cell's contentView as a subview. You should remove all such views in prepareForReuse or you could find cell reuse makes extra buttons appear in cells you don't want to have buttons. Because of the need to prepare cells for reuse it is probably best to subclass UITableViewCell and to provide methods on the subclass to add buttons.
Another way is to register multiple kinds of cells for reuse with the table view, choosing what kind of cell to retrieve and use based on the data backing your table view. This is as simple as using registerClass:forCellReuseIdentifier: once for each kind of cell, then applying right reuse identifier in dequeueReusableCellWithIdentifier:forIndexPath: - you'll still be subclassing the cell objects but you configure them further in the class rather than at the time they are dequeued.
Use the code below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"cell";
SViewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[SViewTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.cellButton.tag = indexPath.row;
[cell.cellButton addTarget:self action:#selector(clickMe:)
forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (void)clickMe:(UIButton *)sender {
SViewTableViewCell *cell = (SViewTableViewCell *)[[[sender superview]superview] superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self keepSelectionRemainsSameForIndexPath:indexPath andSender:sender];
}
- (void)keepSelectionRemainsSameForIndexPath:(NSIndexPath *)indexPath andSender:(UIButton *)sender {
if (sender.tag == indexPath.row) {
if ([sender.titleLabel.text isEqualToString: openStr]) {
[sender setTitle:closeStr forState:UIControlStateNormal];
} else {
[sender setTitle: openStr forState:UIControlStateNormal];
}
}
}
I have a Tableview and i am using the customTableview cell for displaying the cell
in the cell i have 5 buttons (rating buttons) when i click on particular button the image of the button has to changed its working fine but when i am scrolling the tableview again thay are changing to normal rating buttons see the following images for clarity
This is the image before scrolling and clicking nothing on button
after clicking the on rating buttons the image is changing like this
but when scrolling the cells again its changing to first image
please help me out
Code :
- (UITableViewCell )tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
dataCell = (DataCel)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (dataCell==nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"DataCel" owner:self options:nil]; dataCell = [nib objectAtIndex:0];
}
return dataCell;
}
you should save the sate of the button images
and in your
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
insert code to keep them updated
for ex:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
//create your cell here if it was not created
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
[cell.textLabel setFont:[UIFont boldSystemFontOfSize:13]];
[cell.textLabel setTextColor:[UIColor darkGrayColor]];
[cell.detailTextLabel setFont:[UIFont boldSystemFontOfSize:11]];
[cell.detailTextLabel setTextColor:[UIColor lightGrayColor]];
cell.detailTextLabel.numberOfLines = 2;
}
NSArray *array = [imageArray objectAtIndex:[indexPath row]];
if([[array objectAtIndex:3] isEqual:#"rate3"])
{
//set the code for the rating 3
}
else
{
//insert another rate depending on your object
}
This is because every time you scroll the UITableView, it refreshes its values from the data you provided it ! So the value is not retained. To prevent this from happening every time you scroll the database you can use this
static NSString *cellIdentifier = #"Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
}
for(id obj in cell.contentView.subviews)
{
if([obj isKindOfClass:[UIImageView class]] || [obj isKindOfClass:[UILabel class]])
{
[obj removeFromSuperview];
}
}
This would not let the values be overlapped.
When scrolled the cells are recreated and so you need the keep the selected values in a seperate array and set it in the cellForRowAtIndexPath method
This happens because every time you scroll the tableview , it re-create tableview cell. therefor you can use array for reused it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellId = #"cellId";
UITableViewCell *cell = [categoriesTableview dequeueReusableCellWithIdentifier:cellId];
if (cell==nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
// ui goes here
return cell
}
I created custom cells for my table. Basically my cells have UIButton on them. I am reusing those cells.
However i have trouble with those buttons, because when cells is reused then all it's elements also is reused but i am seeking that these Button will be unique to every cells.
Maybe someone could propose a solution for this functionality ?
How about this if you have a property button on your custom cell?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath static NSString *CellIdentifier = #"My Cell Identifier";
MyCustomCellClass *cell = (MyCustomCellClass *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyCustomCellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
UIButton *myButtonForThisCell = [MyButtonArray objectAtIndex:indexPath.row];
cell.button = myButtonForThisCell;
return cell;
}
create a buttonView UIVIEW file with two methods as
-(NSInteger) getGridIndex
{
return gridIndex;
}
-(void) setGridIndex:(NSInteger)value
{
gridIndex = value;
}
Now in cellforrowatindexpath method
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
ButtonView *buttonView=[[ButtonView alloc] initWithFrame:CGRectMake(110, 110, 160, 26)];
buttonView.tag=18;
UIButton *button=[[UIButton alloc]initWithFrame:CGRectMake(55, 0, 60, 26)];
[button addTarget:self action:#selector(ButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[buttonView addSubview:button];
[cell addSubview:buttonView];
}
ButtonView *buttonView=(ButtonView*)[cell viewWithTag:18];
NSArray *d=[buttonView subviews];
UIButton *button=[d objectAtIndex:0];
//here you can change the setting or title of button or whatever u want to do.
[buttonView setGridIndex:indexPath.row];
}
Now in button action :
-(void)ButtonAction:(UIButton*)sender{
ButtonView *view = (ButtonView *)[sender superview];
NSInteger n=[view getGridIndex];
//here n is the indexpath.row at which the button was tapped..you can write its action accordingly.
}
I implemented a UIButton in every cell of my UITableView and set an action for this button. Now I'm trying to find out which of these buttons was tapped:
- (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];
}
// Configure the cell...
<...>
UIButton *but=[UIButton buttonWithType:UIButtonTypeRoundedRect];
but.frame= CGRectMake(275, 5, 40, cell.frame.size.height-10);
[but setTitle:#"Map" forState:UIControlStateNormal];
[but addTarget:self action:#selector(Map:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:but];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
- (IBAction) Map: (id) sender {
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
indexPath = [tableView indexPathForCell:(UITableViewCell*)[[sender superview]superview]];
[delegate callMap: [[[data objectAtIndex:indexPath.section]
objectAtIndex:indexPath.row+1]
objectAtIndex:kNameInArray]
: [[[[data objectAtIndex:indexPath.section]
objectAtIndex:indexPath.row+1]
objectAtIndex:kXcoordinateInArray] doubleValue]
: [[[[data objectAtIndex:indexPath.section]
objectAtIndex:indexPath.row+1]
objectAtIndex:kYcoordinateInArray] doubleValue]
];
}
But it always sends data[0][1][*] elements to the delegate. I mean indexPath always has 0 raw and 0 section. Where is my mistake?
Do the following:
add the button inside your if (cell == nil) { ... } method or else you will have lots of buttons inside the same cell when your cell is reused.
Set cell.contentViow.tag = SomeValueIdentifyingYourData (some int value representing your model.. maybe just the index of your object array..) before returning the cell.
Inside your Map: method you can access the value again with ((UIButton)sender).superview.tag and make your decisions based on that value