I am using table view using custom coding with tag method to save memory.
I was successful to show data in the view but the problem is if 10 cells are showing and then if I scroll down like for one cell then it should show 2-11 cell data but it switches to 1-10 again.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UILabel *cellNAMElabl = nil;
UILabel *cellDetaillabl = nil;
UIImageView *imgView = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
[cellNAMElabl setTag:1];
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
UIFont *myFont1 = [ UIFont fontWithName: #"Arial" size: 20.0 ];
cellNAMElabl.font = myFont1;
[cell.contentView addSubview:cellNAMElabl];
cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
[cellDetaillabl setTag:2];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 13.0 ];
cellDetaillabl.font = myFont;
[cell.contentView addSubview:cellDetaillabl];
imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
[imgView setTag:3];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
}
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
You are not assigning new content to subviews, if they have been already created. After the case if(cell == nil), these you have just got references.
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
Here when cell is not nil, you are just getting references to labels and imageview, but you are not setting new text and image from data source. Add following lines and remove them from the if (cell == nil) part:
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
The way this dequeueReusableCellWithIdentifier works: If iOS detects that a cell is not displayed anymore, then dequeueReusableCellWithIdentifier will return that cell. If there is no unused cell, it returns nil. So what you need to do:
If dequeueReusableCellWithIdentifier returns nil, then you create a new cell, and you do all the setup that is required for all cells with the same identifier. For example, add view tags like you did, set fonts, colors etc.
Then, whether you use a cell returned by dequeueReusableCellWithIdentifier or one that you just created yourself, you add all the information that is used for the specific section/row that you want to display. So if row 1, row2, and so on display different text, then you set the text here. That's what you didn't do, so when a cell was reused, you didn't set the new text for it.
So the idea is that all the work that is the same for all rows is only done once when a cell is created, and only as many cells are created as is needed to display them on the screen. The work that is different from row to row is done for each row, as it is needed.
If you set a breakpoint in the if cell == nil block its probably only being hit for the first set if your reuseID is correct. Thats why its never getting a chance to set any new data into the cell.
You should not look for a nil cell, rather use a correct reuseID and a prototype cell in IB that is set to a custom UITableViewCell subclass you create.
Its also good practice to implement prepareForReuse on custom cells, where you clear any cell data e.g. label.text = nil, imageview.image = nil
This way you dont get invalid data from previously dequeued cells. It might not solve the question directly, but it would have wiped the fixed data set in your if cell == nil block to help debug.
What you want to do is..
add/setup the tableViewCell UI if the cell is nil..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
UILabel *cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
cellNAMElabl.tag = 1;
cellNAMElabl.font = [UIFont fontWithName: #"Arial" size: 20.0 ];
[cell.contentView addSubview:cellNAMElabl];
UILabel *cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
cellDetaillabl.tag = 2;
cellDetaillabl.font = [UIFont fontWithName: #"Arial" size: 13.0 ];
[cell.contentView addSubview:cellDetaillabl];
UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
imgView.tag = 3;
[cell.contentView addSubview:imgView];
}
//and just update your data if the cell is currently exist and not nil..
//you already called the view using tag so, you dont need those:
// UILabel *cellNAMElabl = nil;
// UILabel *cellDetaillabl = nil;
// UIImageView *imgView = nil;
((UILabel *)[cell viewWithTag:1]).text = [name5 objectAtIndex:indexPath.row]; // cellNAMElabl
((UILabel*)[cell viewWithTag:2]).text = [email5 objectAtIndex:indexPath.row]; // cellDetaillabl
((UIImageView*)[cell viewWithTag:3]).image = [imagepath5 objectAtIndex:indexPath.row]; // imgView
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
hope this have help you, happy coding cheers!
Related
I have custom cell in my UITableView and according to the string's value I want to add a UILabel in the cell.
Here is my code for cell,
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * tmpDictn = [tableAry objectAtIndex:indexPath.section];
NSString * typeStr = [tmpDictn objectForKey:#“DocumentType”];
NSString * cellIdentifier = #"TestCell";
TestCell *cell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell){
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if ([typeStr isEqualToString:#“Text”]) {
UILabel * textLbl = [[UILabel alloc] init];
textLbl.backgroundColor=[UIColor clearColor];
textLbl.textColor=[UIColor lightGrayColor];
textLbl.userInteractionEnabled=NO;
textLbl.numberOfLines = 0;
textLbl.font = [UIFont fontWithName:#“Helvetica" size:16];
[textLbl setFrame:CGRectMake(30, 20, 250, 25)];
textLbl.text= [NSString stringWithFormat:#"%# %i",[splitAry objectAtIndex:i],indexPath.section];
[cell addSubview:textLbl];
}
}
return cell;
}
My UITableView contain 5 cell(dynamic). And only first cell should have this label(this also change according to Text). This code is adding UILabel in first cell but also add UILabel at 3 and 5th cell.
I have checked that its same UILabel created 1 time and added in cell 1st, 3rd and 5th. And "Text" is only at first position in Tableary.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * tmpDictn = [tableAry objectAtIndex:indexPath.section];
NSString * typeStr = [tmpDictn objectForKey:#“DocumentType”];
NSString * cellIdentifier = #"TestCell";
TestCell *cell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell){
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *lbl = [cell viewWithTag:1];
if(lbl)
{
[lbl removeFromSuperView];
}
if ([typeStr isEqualToString:#“Text”]) {
UILabel * textLbl = [[UILabel alloc] init];
textLabel.tag = 1;
textLbl.backgroundColor=[UIColor clearColor];
textLbl.textColor=[UIColor lightGrayColor];
textLbl.userInteractionEnabled=NO;
textLbl.numberOfLines = 0;
textLbl.font = [UIFont fontWithName:#“Helvetica" size:16];
[textLbl setFrame:CGRectMake(30, 20, 250, 25)];
textLbl.text= [NSString stringWithFormat:#"%# %i",[splitAry objectAtIndex:i],indexPath.section];
[cell addSubview:textLbl];
}
}
return cell;
}
Try using a different cell identifier for the cells that need a label added to them, e.g. #"TextCell". Otherwise, you are reusing cells that already have a label added even if it is not supposed to be there. Alternatively, you could remove the label (if it is there) in an 'else' condition of your if ([typeStr isEqualToString:#“Text”]) block but I think that the former is cleaner.
You are using
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
The problem for your code is that table view is reusing your cell. So it will appear in many as your number of cells increases.
I am a bit old programmer but I think the best way is to
if (!cell)
{
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//Add your label here.
}
if(!label)
{ //your code;
//set label text to nil if your condition not met;
}
A quick solution for you is to put an else and set text to nil;
Cheers.
CoreData returns BOOL value and according to the value I draw a UILabel on UITableViewCell accessoryView. The problem is that UILabel repeats itself also on the cells it shouldn't appear at all.
CGRect lblRect = CGRectMake(230, 7, 20, 20);
UILabel *lblEnabled = [[UILabel alloc] initWithFrame:lblRect];
lblEnabled.textColor=[UIColor whiteColor];
lblEnabled.textAlignment=NSTextAlignmentCenter;
[lblEnabled setFont:[UIFont fontWithName:#"Verdana" size:10.0]];
[lblEnabled setText:#"40"];
lblEnabled.backgroundColor= [UIColor colorWithPatternImage:[UIImage imageNamed:#"greenBg"]];
lblEnabled.layer.cornerRadius = 9.0;
lblEnabled.layer.masksToBounds = YES;
lblEnabled.tag = indexPath.row;
cell.accessoryView = lblEnabled;
[cell.contentView addSubview:lblEnabled];
So it appears sometimes on the cell where the BOOL value = NO; Your help is strongly appreciated.
EDIT: I draw these labels in cellForRowForIndexPath.
EDIT: I use storyboards, so I don't check if cell is nil.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
/*
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
tableView.rowHeight=57.0;
}*/
Coin *coin=[[self frcFromTV:tableView ] objectAtIndexPath:indexPath];
cell.textLabel.text=coin.coinNominal;
if(coin.comSubject.length>0)
{
cell.detailTextLabel.text=[NSString stringWithFormat:#"%#%# (%#) | %#",[self returnCatalogDefinition:coin.catalogIndex],coin.kmRef, coin.dates, coin.comSubject];
}
else
{
cell.detailTextLabel.text=[NSString stringWithFormat:#"%#%# | %#",[self returnCatalogDefinition:coin.catalogIndex],coin.kmRef,coin.dates];
}
if(coin.isCommemorative.boolValue)
{
// implement label
}
if(coin.listed.boolValue)
{
CGRect lblRect = CGRectMake(230, 7, 20, 20);
UILabel *lblEnabled = [[UILabel alloc] initWithFrame:lblRect];
lblEnabled.textColor=[UIColor whiteColor];
lblEnabled.textAlignment=NSTextAlignmentCenter;
[lblEnabled setFont:[UIFont fontWithName:#"Verdana" size:10.0]];
[lblEnabled setText:#"40"];
lblEnabled.backgroundColor= [UIColor colorWithPatternImage:[UIImage imageNamed:#"greenBg"]];
lblEnabled.layer.cornerRadius = 9.0;
lblEnabled.layer.masksToBounds = YES;
lblEnabled.tag = indexPath.row;
cell.accessoryView = lblEnabled;
[cell.contentView addSubview:lblEnabled];
}
return cell;
}
In code below you probably add your label but because those cells are reusable you should handle else statement (hiding label or whatever is appropriate)
if(coin.isCommemorative.boolValue)
{
// implement label
//remove from that part of the statement this line:
//[cell.contentView addSubview:lblEnabled];
} else {
cell.accessoryView = nil;
//hiding or modifying label for other cases
}
if you will not deal with that else statement the change you made in if will be applicable to more than one cell because of the reusing mechanism
As a "side advice" I would recommend you to subclass UITableViewCell and add the property you want (label) to encapsulate that and make only public method for showing or hiding that accessor.
EDIT:
if your flag for a change is not specifying to which cell it has to indicate (for example using indexPath) then the result is as your one.
This is quite global state if(coin.isCommemorative.boolValue) not indicating to which cell it counts try for example (for just learning purpose) add if(coin.isCommemorative.boolValue && indexPath.row%2==0) and see the result.
Are you reusing cells? If so, then you need to remove that cell from contentView inside prepareForReuse method.
If I have a long text I have to increase the cell size to fit the text.
When I assign: cell.textLabel.text = #"my string" , if the string is long it gets truncated.
How can I display the text in two or more rows for this case? I am using UITableViewCell only and not subclassing it anywhere. Is there some code to display long texts using cell.textLabel directly? I am not talking about adding a seperate view to cell.
cell.textLabel will not allow you to line break a string into two lines. What you will have to do is customize it add your own UILabel to UITableViewCell and define its parameters.
Here's a working code that you can add to your TableView.
//define labelValue1 in your .h file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSLog(#"Inside cellForRowAtIndexPath");
static NSString *CellIdentifier = #"Cell";
// Try to retrieve from the table view a now-unused cell with the given identifier.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// If no cell is available, create a new one using the given identifier.
if (cell == nil)
{
// Use the default cell style.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
labelValue1 = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 200, 100)]; //adjust label size and position as needed
labelValue1.font = [UIFont fontWithName:#"BradleyHandITCTT-Bold" size: 23.0];
labelValue1.textColor = [UIColor whiteColor];
labelValue1.textAlignment = NSTextAlignmentCenter;
labelValue1.numberOfLines = 2; //note: I said number of lines need to be 2
labelValue1.backgroundColor = [UIColor clearColor];
labelValue1.adjustsFontSizeToFitWidth = YES;
labelValue1.tag = 100;
[cell.contentView addSubview:labelValue1];
}
else
{
labelValue1 = (UILabel *) [cell viewWithTag:100];
}
// Set up the cell.
NSString *str1 = [arryData3 objectAtIndex:indexPath.row];
labelValue1.text = str1;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Multiple lines can be shown using
cell.textLabel.LineBreakMode = NSLineBreakByWordWrapping
This is for Swift.
cell.textLabel?.numberOfLines = 10 /// or the number you like.
As I scroll up and down the table view the data in each cell becomes duplicated and unreadable. Does anyone have any suggestions for the below?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 250, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
label1.tag= 666;
label2.tag= 666;
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
// Configure the cell...
President *p = (President *)[self.importedRows objectAtIndex:indexPath.row];
label1.text = p.no;
label2.text = p.name;
UILabel* cellLabel = (UILabel*)[cell viewWithTag: 666];
cellLabel.text = [NSString stringWithFormat:p.no , p.name];
return cell;
}
dequeueReusableCellWithIdentifier caches the generated cells. So if you request a cell which you already created before this cell will NOT be generated again from scratch (meaning that the labels you added before already exists!).
So when adding the labels tag them with a unique number :
label1.tag= 666;
label2.tag= 667;
And before adding them to the cell remove them as follows :
UIView *labelView = [cell.contentView viewForTag:666];
if (labelView != nil) {
[labelView removeFromSuperView];
}
And do the same with the second label.
because you are adding label1 and label2 again and again to cell.
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 250, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
As the cell is reused, same cell is used for another row, and it already has label1,2. but you are creating label1,2 again and again and adding them to it.
Give different tags for label1,label2.Check if viewWithTag:666 and 667 is present.If not present add them as subview ,if already present, just get them using viewWithTag and change their text values.
The problem here is with below code:
UILabel* cellLabel = (UILabel*)[cell viewWithTag: 666];
cellLabel.text = [NSString stringWithFormat:p.no , p.name];
I have tried your code, commenting these two lines stop overlapping. You can try to change the frame of this label.
I suggest making your own subclass of UITableViewCell which has two UILabel's on it, then in the method you're using above, create instances of your subclass rather than UITableViewCell if the cell doesn't exist, then populate the labels.
In your custom cell implementation file, you'll have to override the 'prepareForReuse' method, and in it set the text of your labels to nil (#""). This properly uses the 'dequeueWithReuseIdentifier' functionality and only creates the labels when necessary, rather than only showing them when required.
A solution where you can gain performance is the following.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// create and add labels to the contentView
}
// retrieve and update the labels
Obviously you could also create your UITableViewCell subclass.
You could also try this swag (fresh answer, get your fresh answer!):
BOOL doesContain = [cell.subviews containsObject:imageView];
if (!doesContain)
{
[cell.contentView addSubview:imageView];
}
imageView.image = yourImage];
Also for a quick way to subclass all of your stuff, check my answer.
I'm having problems implementing a table row that allows text to wrap to multiple lines, and also has an image on the left, and a disclosure accesssory on the right.
The multiline text is fine but the imageView expands to the right when there is more than one line of text. I want images in all rows to be the same size. I've tried setting the autoresizingMask to UIViewAutoresizingNone but this doesn't seem to work.. Do I need to use the contentView, or a nib file?
Any help/example code appreciated!
If all off your images are different size then you should think of adding a ImageView as Subview to cell. Keep Labels depending on the Imageview.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
UIImageView *cellImage;
UILabel *label;
UILabel *detailLabel;
cell = [tableView dequeueReusableCellWithIdentifier:#"cell"]; //Create cell
if(cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"] autorelease];
cellImage = [[[UIImageView alloc] initWithFrame:CGRectMake(3, 3, 44, 44)] autorelease];
label = [[[UILabel alloc] initWithFrame:CGRectMake(55, 4, 260, 20)] autorelease];
label.font = [UIFont boldSystemFontOfSize:15.0];
label.tag=25;
detailLabel = [[[UILabel alloc] initWithFrame:CGRectMake(55, 25, 260, 15)] autorelease];
detailLabel.font = [UIFont systemFontOfSize:13.0];
detailLabel.tag=30;
[cell.contentView addSubview:cellImage];
[cell.contentView addSubview:label];
[cell.contentView addSubview:detailLabel];
cell.accessoryType =UITableViewCellAccessoryDisclosureIndicator;
}
else
{
cellImage = (UIImageView *)[cell.contentView viewWithTag:20];
label = (UILabel *)[cell.contentView viewWithTag:25];
detailLabel = (UILabel *)[cell.contentView viewWithTag:30];
}
cell.image = [arrayContainingImages objectAtIndex:indexPath.row];
label.text =[arrayContaininglabeltext objectAtIndex:indexPath.row];
detailLabel.text=[arrayContainingDetailLabelText objectAtIndex:indexPath.row];
return cell;
}
pls see Stop image expanding in multiline table row? #2