Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a subview larger than cellHeight to a UITableViewCell?

I'm trying to add a subview to a UITableViewCell and the design that I'm working from demands that this particular subview (an image) needs to be larger than the actual UITableViewCell and thus partly overlap its siblings.

So I've set up my table cell, generated my image and added it to the cell's contentView:

// rowHeight for the UITableView is 45.0f

UIImage *image = [self createCellThumbnail: someImage];
UIImageView *thumbView = [[UIImageView alloc] initWithFrame: CGRectMake(150, -5, 55,55)];
thumbView.transform = CGAffineTransformMakeRotation(0.1f);
thumbView.image = image;

cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;

[cell.contentView addSubview: thumbView];

While the image will 'overflow' into the cell below it, the top of the image is always clipped, as demonstrated here:

img

Does anyone know if what I'm trying to do is possible with the current approach?

Or should I just figure out a way to draw these images onto the UITableView after all the cells are drawn (it's a non-scrollable tableview, so that would work and be fairly easy).

Update:

Have also tried adding the following, to no avail:

cell.opaque = NO;
cell.contentView.opaque = NO;

cell.clearsContextBeforeDrawing = NO;
cell.contentView.clearsContextBeforeDrawing = NO;

cell.clipsToBounds = NO;    
cell.contentView.clipsToBounds = NO;
like image 708
NSSec Avatar asked May 16 '10 07:05

NSSec


3 Answers

I seems that the tableView renders its cell from bottom to top, so the cells above one cell overlap that one cell. To avoid this, you'd have to set the backgroundColor of all cells to +[UIColor clearColor] so that you won't see those overlap problems.

But setting the backgroundColor to clear in -tableView:cellForRowAtIndexPath: does not make any sense. UIKit does a lot of stuff with the cell before it's drawn, so does it reset the backgroundColor property of the cell.

What we need to do is setting the backgroundColor in a later state. Luckily there is this -[UITableViewDelegate tableView:willDisplayCell:forRowAtIndexPath:] which we can implement like this:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.backgroundColor = [UIColor clearColor];
}

Now we're setting the backgroundColor just before the cell is drawn an this turns out to be working.

like image 152
Joost Avatar answered Nov 15 '22 14:11

Joost


UPDATE:

So I've done some more experimentation and the following solution still works without having to set the background of the cell to transparent, this involved moving the z order of the covered cell. This works with highlighting and selecting of the other cell (via the relevant callbacks), and if the two cell's backgrounds are different colors. Solution is as follows (you can ignore the didHighlight and didSelect methods if they don't matter to you):

(note that "covered row" is the one whose content we are trying to keep visible and In my case its content goes slightly into the row above, which was clipping it)

-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0 && indexPath.row == ROW_ABOVE_COVERED_ROW)
    {
        NSIndexPath * rowbelow = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
        UITableViewCell* cell = [tableView cellForRowAtIndexPath:rowbelow];
        [cell.superview bringSubviewToFront:cell];
    }
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0 && indexPath.row == ROW_ABOVE_COVERED_ROW)
    {
        NSIndexPath * rowbelow = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
        UITableViewCell* cell = [tableView cellForRowAtIndexPath:rowbelow];
        [cell.superview bringSubviewToFront:cell];
    }
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 && indexPath.row == COVERED_ROW)
    {
        [cell.superview bringSubviewToFront:cell];
        cell.contentView.superview.clipsToBounds = NO;
    }
}

NOTE: you should also set the background color of your content to clear, or it will adopt the bgcolor of the rest of your cell, and so when you manage to bring your content to the front of the covering cell, it will take the background color with it and leave a nasty looking block in the other cell (in my case my only content was the detailTextLabel and the textLabel):

// in cellForRowAtIndexPath:
[cell setBackgroundColor:[UIColor redColor]]; //using red for debug
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.backgroundColor = [UIColor clearColor];

I hope that's helpful to anyone else trying this....

ORIGINAL:

For me the solution was to use:

self.contentView.superview.clipsToBounds = NO;

My cells were already transparent, but my content was still getting clipped. In my case I was using a custom cell which moves it's content up in layoutSubviews. So layoutSubviews for my custom cell wound up as follows:

-(void)layoutSubviews
{
    [super layoutSubviews];
    self.contentView.frame = CGRectOffset(self.contentView.frame, 0, -11);
    self.contentView.superview.clipsToBounds = NO;
}

I don't know if this would work if the cell above was opaque, or if the cells were to highlight when pressed, whether this would cover up my content.

However, I didn't need to make the cell transparent again in the viewWillDisplayCell callback method - doing it in the normal cellForRowAtIndexPath was sufficient

like image 21
Sam Avatar answered Nov 15 '22 15:11

Sam


I had this problem and I made sure my custom tableviewcell's main background had clip subviews checked and it solved the problem. This was with a custom tableview cell loaded from a xib though. Not exactly the same but similar situation.

like image 2
mike Avatar answered Nov 15 '22 14:11

mike