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
Related
How to create the following UITableView in a VC with 2 Columns? As UITableView only has one column. Is it possible to do it in StoryBoard? How to add shadow, round the corners and add the blurish borders as in the pic? All help or pointer is greatly appreciated.
Edited
How to set the 2 columns in Objective C? I can't find any help over the net especially for objective C. I think both the columns are UILabel.
As for the rows, do I need to set the Prototype Cell to 3 at Story Board?
The 1st column will have static values: NAME, DATE OF BIRTH, LOCATION. The 2nd column will fetch data from an array [John Doe, 06.03.1991, New York]
Do I create a loop to insert the data?
ANSWER
I followed this link and managed to create 2 custom UILabel columns and insert the columns from NSMutableArray
I can't get the following suggested answer to work, the answer suggested that we create an Empty User Interface and then add a Table View Cell and associate it back to the VC. I can't get it to work.
Mine was just creating the 2 labels at the prototype cell at the TableView and then following the link above.
create a customcell and put 7 UILabel first 4 label gives name basic setting,NAME,DOB,LOCATION than remain 3 label set blank and give tham property in cell.h file
#pragma mark tableview delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [yourdataarray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourcustomcellname"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"yourcustomcellname" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
id object = [yourdataarray objectAtIndex:indexPath.row];
if ([object isKindOfClass:[NSMutableArray class]]) {
NSMutableArray *Array = (NSMutableArray *)object;
//your cell property use here for fatch like below
[cell.NAME setText:[NSString stringWithFormat:#"%#",[Array objectAtIndex:i]]];//here i=which index your array contain name data
}
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return yourcustomcellheight;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}
refer this tutorial for customcell
https://www.appcoda.com/customize-table-view-cells-for-uitableview/
You need to use custom UITableViewCell, it seems the first column is just a label and the second column is a textfield.
In order to add boundary and add corner
myTableViewCell.contentView.layer.borderColor = [[UIColor grayColor] CGColor];
myTableViewCell.contentView.layer.borderWidth = 1;
myTableViewCell.contentView.layer.cornerRadius = 5.0;
myTableViewCell.contentView.clipsToBounds = YES;
myTableViewCell.contentView.layer.masksToBounds = YES;
check following example as a reference to learn how to create Custom UITableViewCell and use.
https://www.appcoda.com/ios-programming-customize-uitableview-storyboard/
These columns you need to design in UITableViewCell. It can be anywhere of your preference, storyboard or xib.
For storyboard your view will be like this.
you need to add tags for all the components you add into the cell
- (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];
}
...
...
UILabel *label1 = (UILabel *)[cell viewWithTag:100];
label1.text = #"NAME";
UILabel *label2 = (UILabel *)[cell viewWithTag:200];
label2.text = #"John";
...
...
return cell;
}
The same way if you create xib your custom cell should be like this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
StackTableviewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = (stackTableviewCell*)[[[NSBundle mainBundle] loadNibNamed:#"StackTableviewCell" owner:self options:nil] objectAtIndex:0];
}
...
...
label1.text = #"NAME";
label2.text = #"John";
...
...
}
For cell UI
self.lable1.backgroundColor = [UIColor lightGrayColor];
self.lable1.layer.borderColor = [UIColor colorWithRed:169/255.0 green:169/255.0 blue:169/255.0 alpha:0.8].CGColor;
self.lable1.layer.borderWidth = 1;
self.lable1.layer.cornerRadius = 5;
self.lable1.clipsToBounds = YES;
self.lable1.layer.masksToBounds = YES;
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
}
here i have a table view where i'm adding custom label which stores some
quiz ids from array
where cell.textlabel.text stores quiz names from array
problem:
when i'm selecting first row in didselectRowAtIndexPath
it returns cell.textlabel.tex but for second row it is returning correct value that is
quiz ids
here is code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [quizname objectAtIndex:indexPath.row];
UILabel *lbl = [[UILabel alloc]init];
lbl.tag=indexPath.row;
[cell addSubview:lbl];
lbl.text = [quizIds objectAtIndex:indexPath.row];
return cell;
}
in did selectrow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *label = (UILabel *) [cell viewWithTag:indexPath.row];
NSString *qid =label.text;
NSLog(#"%#",qid);
}
i'm getting quid is equal to cell.texlabel.text for firsr row but not in others rows
they are getting quiz ids perfectly
any help most valueble for me
Try using customTableViewCell & add your label inside the customCell. Adding UILabel inside cellForRowAtIndexPath is not a good approach.
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've subclassed the UITableViewCell to add custom appearance to it. At the init level of the MYTableViewCell I added 4 subviews: UIImageView, and three UILabel(s). All 4 subviews have a different Tag assigned to them.
Inside the cellForRowAtIndexPath method I either create a new cell if it wasn't available at first, or reuse available one and assign the proper text to the ui labels.
The problem I am having is that if I try to scroll super fast, then the data gets messed up, however if I scroll up and down more slowly, then everything works fine.
Any thoughts??
Below is the code:
- (MyTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"itemListTableViewCell";
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
DisplayableEntity *displayableEntity = [self.fetchedResultsController objectAtIndexPath:indexPath];
if( ! cell ) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[self tableView:tableView appearanceForCell:cell withEntity:displayableEntity];
} else {
UIImageView *imageView = (UIImageView *) [cell viewWithTag:IMAGEVIEW_TAG];
imageView.image = [UIImage imageNamed:displayableEntity.displayImageName];
UILabel *titleLabel = (UILabel *) [cell viewWithTag:TITLEVIEW_TAG];
titleLabel.text = displayableEntity.entityName;
UILabel *itemDescription = (UILabel *) [cell viewWithTag:DESCRIPTION_TAG];
itemDescription.text = displayableEntity.entityDesctiption;
}
}
// some code removed to make it brief
- (void)tableView:(UITableView *)tableView appearanceForCell:(MyTableViewCell *)cell withEntity:(DisplayableEntity *)entity {
// cell image view
UIImageView *cellImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[entity displayImageName]]];
[cellImageView setTag:IMAGEVIEW_TAG];
[cell addSubview:cellImageView];
// adding entity name label
UILabel *itemTitleName = [self itemTitleNameLabelWithFrame:itemNameLabelRect itemName:[entity entityName]];
[itemTitleName setTag:TITLEVIEW_TAG];
[cell addSubview:itemTitleName];
// adding 'assigned to' label right under the item name label
UILabel *itemDescriptionLabel = [self itemDescriptionLabelWithFrame:descriptionLabelFrame itemDescription:[entity entityDesctiption]];
[itemDescriptionLabel setTag:DESCRIPTION_TAG];
[cell addSubview:itemDescriptionLabel];
}
I see some troubles in tableView:cellForRowAtIndexPath: logic
It should be:
Dequeue cell
If cell cannot be dequeued - create the new one
Set all cell properties
I mean something like this:
- (MyTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"itemListTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
} // <-- Note there is no else, we should reset properties in both cases
NSManagedObject *managedObject = [_fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [managedObject valueForKey:#"text"];
cell.imageView.image = [managedObject valueForKey:#"image"];
return cell;
}