Varun Naharia
Varun Naharia

Reputation: 5420

UIButton overlapping and hidden unexpectedly inside UITableViewCell

I have created aUIButton programmatically inside the customUITableViewCell, No. ofUIButtons inside the cell is dynamic and at first it looks working perfect but when I open all the collapsed cell and scroll the table view UIButton overlap each other and If I scroll more the the UIButton in view outside the screen become hidden when thy come back to screen area here is image what it looks like.

I am not posting code here because its big and I don't know which part should I include here. If asked I will post that particular code here.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    InterestTableViewCell *cell = (InterestTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    NSString *category= (NSString *)[self.itemsInTable objectAtIndex:indexPath.row];
    NSMutableArray *subcat =[[NSMutableArray alloc] init];
    NSArray *keys = [cat allKeys];
    id aKey = [keys objectAtIndex:indexPath.row];
    subcat = [cat objectForKey:aKey];
    cell.btnGroupTap.tag = indexPath.row+10000;
    NSArray *count=(NSArray *)subcat;
    int xoffset;
    int yoffset = 0;
    for(int i=0; i<count.count;i++)
    {
         if(i==0)
        {
            xoffset=0;
        }
        else
        {
            if(i%2 == 0)
            {
            xoffset = 0;
            }
            else
            {
                xoffset = 150;
            }
        }
        if(i==0)
        {
            yoffset = 0;
        }
        else
        {
            if(i%2==0)
            {
                yoffset = yoffset+45;
            }
        }
        NSString *sel = subcat[i][@"selected"];
        NSString *key =subcat[i][@"key"];
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        UIImage *image;
        if(![sel boolValue])
        {
            image = [UIImage imageNamed: @"unchecked.png"];
        }
        else
        {
            image = [UIImage imageNamed: @"checked.png"];
        }
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(29,18,20,20)];
        [imageView setImage:image];
        UILabel *lbl1 = [[UILabel alloc] init];
        [lbl1 setFrame:CGRectMake(0,5,100,20)];
        lbl1.backgroundColor=[UIColor clearColor];
        lbl1.textColor=[UIColor blackColor];
        lbl1.frame = CGRectMake(40,0,100,40);
        lbl1.numberOfLines =0;
        [lbl1 setFont:[UIFont fontWithName:@"Roboto-Light" size:12]];
        lbl1.text= subcat[i][@"value"];
        button.tag= [key integerValue];
        [button setTitle:@"" forState:UIControlStateNormal];
        button.imageView.contentMode = UIViewContentModeScaleAspectFit;
        [button setBackgroundImage:image forState:normal];
        CGRect screenRect = [[UIScreen mainScreen] bounds];
        CGFloat screenWidth = screenRect.size.width;
        button.frame = CGRectMake(xoffset,20+yoffset,(screenWidth/2)-40,40);
        [button addTarget:self action:@selector(CheckAction:) forControlEvents:UIControlEventTouchUpInside];
        [button addSubview:lbl1];
        [cell.ContainerView addSubview:button];
        [cell.ContainerView bringSubviewToFront:button];
    }
    cell.ContainerView.hidden=YES;
    cell.lblCategory.text = category;
    return cell;
}

Full Code at github

Note: I used [tableView beginUpdates];[tableView endUpdates]; in didSelectRowAtIndexPath.

Upvotes: 0

Views: 444

Answers (2)

Sanjay Mohnani
Sanjay Mohnani

Reputation: 5967

As you are using reusable cells via dequeueReusableCellWithIdentifier: so if the cell is reused it will be already having the previously added CategoryView (basically subviews). You need to remove them first and than ass the new ones, you need to do it as

for (UIView *subview in cell.ContainerView.subViews) {
    if ([subview isKindOfClass:[UIButton class]]) {
        [((UIButton *) subview) removeTarget:nil
                       action:NULL
             forControlEvents:UIControlEventAllEvents];  
        [subview removeFromSuperview];
    }
}

Add above method inside cellForRowAtIndexPath: method as-

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    InterestTableViewCell *cell = (InterestTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    for (UIView *subview in cell.ContainerView.subViews) {
     if ([subview isKindOfClass:[UIButton class]]) {
          [((UIButton *) subview) removeTarget:nil
                                        action:NULL
           forControlEvents:UIControlEventAllEvents];  
          [subview removeFromSuperview];
        }
    }

    NSString *category= (NSString *)[self.itemsInTable objectAtIndex:indexPath.row];
        NSMutableArray *subcat =[[NSMutableArray alloc] init];
        NSArray *keys = [cat allKeys];
        id aKey = [keys objectAtIndex:indexPath.row];
        subcat = [cat objectForKey:aKey];
        cell.btnGroupTap.tag = indexPath.row+10000;
        NSArray *count=(NSArray *)subcat;
        int xoffset;
        int yoffset = 0;
        for(int i=0; i<count.count;i++)
        {
             if(i==0)
            {
                xoffset=0;
            }
            else
            {
                if(i%2 == 0)
                {
                xoffset = 0;
                }
                else
                {
                    xoffset = 150;
                }
            }
            if(i==0)
            {
                yoffset = 0;
            }
            else
            {
                if(i%2==0)
                {
                    yoffset = yoffset+45;
                }
            }
            NSString *sel = subcat[i][@"selected"];
            NSString *key =subcat[i][@"key"];
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            UIImage *image;
            if(![sel boolValue])
            {
                image = [UIImage imageNamed: @"unchecked.png"];
            }
            else
            {
                image = [UIImage imageNamed: @"checked.png"];
            }
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(29,18,20,20)];
            [imageView setImage:image];
            UILabel *lbl1 = [[UILabel alloc] init];
            [lbl1 setFrame:CGRectMake(0,5,100,20)];
            lbl1.backgroundColor=[UIColor clearColor];
            lbl1.textColor=[UIColor blackColor];
            lbl1.frame = CGRectMake(40,0,100,40);
            lbl1.numberOfLines =0;
            [lbl1 setFont:[UIFont fontWithName:@"Roboto-Light" size:12]];
            lbl1.text= subcat[i][@"value"];
            button.tag= [key integerValue];
            [button setTitle:@"" forState:UIControlStateNormal];
            button.imageView.contentMode = UIViewContentModeScaleAspectFit;
            [button setBackgroundImage:image forState:normal];
            CGRect screenRect = [[UIScreen mainScreen] bounds];
            CGFloat screenWidth = screenRect.size.width;
            button.frame = CGRectMake(xoffset,20+yoffset,(screenWidth/2)-40,40);
            [button addTarget:self action:@selector(CheckAction:) forControlEvents:UIControlEventTouchUpInside];
            [button addSubview:lbl1];
            [cell.ContainerView addSubview:button];
            [cell.ContainerView bringSubviewToFront:button];
        }
    cell.ContainerView.hidden=YES;
    cell.lblCategory.text = category;
    return cell;
}

Note: Also if you are using manual memory management scheme for memory management than you need to properly balance the retain count of your objects, for example after creating any subview and adding it fire a release message there. And finally remove it from superview if it's no longer required. I have added these removeFromSuperView/ release statements in your cellForRowAtIndexPath: method.

But as you are using ARC than system will manage the retain /release calls on the object to manage memory

Upvotes: 0

sunshinejr
sunshinejr

Reputation: 4854

The thing is you are using Reusable cells. Think of it as a shopping cart in the market. You will never know if it is new one, maybe you will get one with products already in it. You should always clean your cell in cellForRowAtIndexPath and then proceed with your code.

#edit Seems like cleaning your containerView should help. Like:

InterestTableViewCell *cell = (InterestTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[[cell.ContainerView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

Upvotes: 2

Related Questions