Question

I am using a UITableView and I'm noticing that the cells in my tableview are getting progresively bolder as I scroll, it is overwriting the contents and I want to stop this but can't see where I'm going wrong.

On my UITableView, for some reason when I scroll the contents of the tableview get messed up with the the manually created UILabel.

I require a manual UILabel because I need to have custom cells later on.

As I scroll up and down, the labels get progressively bolder and bolder; they always overlap and sometimes even affects rows lower down (even before they are in the viewport).

If I keep doing it, the cell contents become unintelligable.

This only happens if there the backgroundColor is not set as clearColor.

I have attempted [cellLabel setClearsContextBeforeDrawing:YES]; and [self.tableView setClearsContextBeforeDrawing:YES]; to no effect.

If I use cell.textLabel.text then the problem seems to go away.

Code and an image sample follows.

  // Simple table view
    - (UITableViewCell *)tableView:(UITableView *)tv 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...
        //[self configureCell:cell atIndexPath:indexPath];


        NSString *txt = @"Product";


        //cell.textLabel.text = txt;
        cell.selectionStyle = UITableViewCellSelectionStyleNone;

        UIView *cellView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, cell.frame.size.height)];

        UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
        [cellLabel setText:txt];
        [cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
        [cellLabel setBackgroundColor:[UIColor clearColor]];

        [cellView addSubview:cellLabel];
        [cellLabel release];
        [cell.contentView addSubview:cellView];
        [cellView release];


        return cell;
    }


Image follows;


![image of uitableview][1]


  [1]: http://i.stack.imgur.com/5lNy6.png


// Edit to include context

I am using a dictionary to display the contents of the UITableViewCells.

I have attempted to do the following;

    - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

            [self configureCell:cell atIndexPath:indexPath];
        } // end if


        // Configure the cell...
        //
       // Moved to inside the cell==nil        

        return cell;
    }

-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{

    // Get the txt from the Dictionary/Plist... *removed due verboseness*

    UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
    [cellLabel setText:txt];
    [cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
    [cellLabel setBackgroundColor:[UIColor clearColor]];

    [cell.contentView addSubview:cellLabel];
    [cellLabel release];
}

This, although it fixes the problem of overwriting -- it causes a problem -- it makes labels repeatedly appear in totally random places -- the following is just an example, other fields and labels also repeat.

See picture below;

repeating labels in uitableview

Was it helpful?

Solution

    // cell reuse
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

returned you the cell already been used, it already has an UILabel subview and you are adding another over it. Put the adding subviews at the section

   if (cell == nil) { //cell initialization

and edit the subviews as needed after the cell initialization, you can access them by tag for example.

OTHER TIPS

You are adding the label to the same reused cell every time, that is why it is getting bolder. When you use dequeueReusableCellWithIdentifier, you are grabbing a cell that has already been displayed on the screen, which is the correct thing to do, but you have already put a label on it. As the label will be in the same position relative to the cell each time, and the same color etc.. (the only dynamic element will be the text), you should set all this up only once.

My preferred solution is to create a custom cell with the properties that you want. So in this case, you would create

@interfacce MyCustomCell : UITableViewCell
    @property (nonatomic) UILabel *cellLabel;
@end

Give it a property UILabel *cellLabel, and do all the code you have above apart from setting the labels text in the init of MyCustomCell.m, replace any instances of cell with self, for example:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self)
    {
        self.cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
        [self.cellLabel setText:txt];
        [self.cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
        [self.cellLabel setBackgroundColor:[UIColor clearColor]];
    }

    return self;
}

Now in your cellForRowAtIndexPath use MyCustomCell, where you check if cell == nil, you might want to also check the cell label:

if(cell == nil || cell.cellLabel == nil)

Initialise it in exactly the same way:

cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

now, all you need to do is set:

cell.cellLabel.text = ....;

your code in cellForRowAtIndexPath is a lot cleaner, memory efficient and and you will not get your bug.

Remember to set your cell to be of type MyCustomCell in interface builder.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 

           UITableViewCell *cell = (UITableViewCell*)[self.YourTableName dequeueReusableCellWithIdentifier:nil];        
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
        }


            return cell; 
        }

use ReusablecellIdentifier nil so it working correctly.....

This is a bit older thread. But will be useful to someone,

You can remove any view added to a cell before the same being reused in the tableView.

This code will do that,

for (UIView* view in [cell.contentView subviews])
{
    if ([view isKindOfClass:[UILabel class]])  //Condition if that view belongs to any specific class       
    {
        [view removeFromSuperview];
    }
}

This can be added before configuring the cell,

if (!cell) {
    cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier];

} 

You can also make cell's label values to nil to avoid repetition in trailing cells.

cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
cell.textLabel.font = nil;

Write this code for collectionView. It will help to remove duplicity from reusable cell.

- (void)viewDidLoad {
[super viewDidLoad];
arrImg=[[NSMutableArray alloc]initWithObjects:@"images.jpeg",@"images-2.jpeg",@"images-3.jpeg", nil];

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(375, 200)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];

[self.colView setCollectionViewLayout:flowLayout];
self.colView.backgroundColor=[UIColor lightGrayColor];
self.colView.delegate=self;
self.colView.dataSource=self;

// Do any additional setup after loading the view, typically from a nib.
 }

  -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {


CollectionViewCell1 *cell=(CollectionViewCell1 *)[colView dequeueReusableCellWithReuseIdentifier:@"CollectionViewCell1" forIndexPath:indexPath];
float xAxis=0;
float maxwidth=0;


for (UIView* view in [cell.contentView subviews])
{
    if ([view isKindOfClass:[UIScrollView class]])  //Condition if that view belongs to any specific class
    {
        [view removeFromSuperview];
    }
}
if(indexPath.row==1)
{
    UIScrollView *scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(0,0, colView.frame.size.width, 200)];

    scroll.delegate = self;
    [cell.contentView addSubview:scroll];

    for(int i=0;i<[arrImg count];i++)
    {

    UIImageView *img=[[UIImageView alloc]init];
    xAxis=xAxis+maxwidth;
    img.frame=CGRectMake(xAxis, 0, self.view.frame.size.width, 200);
    img.image=[UIImage imageNamed:[NSString stringWithFormat:@"%@",[arrImg objectAtIndex:i]]];
        [scroll addSubview:img];
        maxwidth=self.view.frame.size.width;
    }

   scroll.contentSize=CGSizeMake(375*3, 200);
   scroll.pagingEnabled=YES;


}
   return cell;

}

Try to not put the UIView *cellView over the UITableViewCell *cell. The UITableViewCell is a subclass of an UIView so you can add subviews if you want. However UITableViewCell has already a label inside.

Just use [cell.textLabel setText:txt].

A-Live's answer was the best solution.

I found https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html to give a much broader example.

However, in my experiments I was able to set up UITableViewCells that did not overwrite, and did not put cell values in random positions.

The code I used is below, it could do with tiyding up, but it seems to work for now;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 120, 35)];
    [cellLabel setFont:[UIFont boldSystemFontOfSize:12]];
    [cellLabel setBackgroundColor:[UIColor clearColor]];
    [cellLabel setTag:1];
    [cell.contentView addSubview:cellLabel];
    [cellLabel release];




    // TextInput setup    
    CGRect cellTextFrame = CGRectMake(200, 12, 65, 30);


    UITextField *txtInputField = [[UITextField alloc] initWithFrame:cellTextFrame];
    [txtInputField setTag:2];
    [txtInputField setDelegate:self];
    [txtInputField setClearButtonMode:UITextFieldViewModeWhileEditing];
    [txtInputField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
    [txtInputField setFont:[UIFont systemFontOfSize:12]];
    [txtInputField setReturnKeyType:UIReturnKeyDone];
    [txtInputField setTextAlignment:UITextAlignmentLeft];
    [txtInputField setKeyboardAppearance:UIKeyboardAppearanceDefault];
    [txtInputField setKeyboardType:UIKeyboardTypeNumbersAndPunctuation];
    [txtInputField setAutocorrectionType:UITextAutocorrectionTypeNo];
    [txtInputField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
    txtInputField.clearButtonMode = UITextFieldViewModeWhileEditing;
    [txtInputField setBorderStyle:UITextBorderStyleRoundedRect];
    txtInputField.textColor = [UIColor colorWithRed:56.0f/255.0f green:84.0f/255.0f blue:135.0f/255.0f alpha:1.0f];
    //[txtInputField addTarget:self action:@selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];     

    [cell.contentView addSubview:txtInputField];
    [txtInputField release];

} // end if


// Configure the cell...
//
//[self configureCell:cell atIndexPath:indexPath];


UILabel *label = (UILabel *)[cell viewWithTag:1];
[label setText:txt];

UITextField *txtField = (UITextField *) [cell viewWithTag:2];
[txtField setText:txtText];
[txtField setPlaceholder:txtPlaceholder];



return cell;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top