如何在UITableViewCell中添加一个比cellHeight更大的子视图?

15

我正在尝试将一个子视图添加到UITableViewCell中,设计要求这个特定的子视图(一张图片)需要比实际的UITableViewCell更大,因此部分重叠其兄弟视图。

因此,我设置了我的表格单元格,生成了我的图片并将其添加到单元格的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];

尽管图像会“溢出”到其下方的单元格中,但图像的顶部始终被裁剪,正如此处所示:

img

有人知道我正在尝试做的事情是否可能?

还是我应该找到一种方法,在所有单元格绘制完之后将这些图像绘制到UITableView上(它是一个不可滚动的UITableView,所以这样做会很容易)。

更新:

也尝试添加了以下内容,但没有效果:

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

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

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

请注意,表视图单元格中的contentView是一个只读属性。 - TigerCoding
4个回答

15

看起来tableView是从底部向上渲染其单元格,因此位于所展示单元格之上的所有单元格都会覆盖该单元格。为避免这种情况,您需要将所有单元格的backgroundColor设置为+[UIColor clearColor],以便您不会“看到”这些重叠问题。

但是在-tableView:cellForRowAtIndexPath:中将backgroundColor设置为clear没有任何意义。 UIKit在绘制单元格之前会对其进行大量处理,因此会重置单元格的backgroundColor属性。

我们需要在稍后的状态下设置backgroundColor。幸运的是,有这个-[UITableViewDelegate tableView:willDisplayCell:forRowAtIndexPath:]方法,我们可以像这样实现:

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

现在我们正在设置 backgroundColor,就在单元格绘制之前,结果看起来很有效。


这个对我很有效。有点奇怪的是,当你在UITableViewCell创建时显式设置backgroundColor时,UIKit随后会说:“好吧,但今天不行,我会使用不透明颜色。”。 - NSSec
1
我添加了一个回答,说明对我有用的方法,可能会帮助到某些人——可能需要结合这两个答案。 - Sam
我更新了我的答案 - 通过更改单元格视图的Z顺序,我们不需要使用透明单元格... - Sam
willDisplayCell 成功了。看起来在界面生成器中设置单元格背景色是不够的。当单元格被重用时,它的背景色似乎会再次设置,这将覆盖其上/下方的单元格。 - hasan
使用这种方法,可以在单元格外成功地对UILabel进行动画处理:iOS9。 - neobie

4

更新:

我进行了更多的实验,以下解决方案依然有效,而且无需将单元格背景设置为透明,这涉及到移动被覆盖单元格的z顺序。这可以通过突出显示和选择其他单元格(通过相关回调函数)来完成,如果两个单元格的背景颜色不同,则此方法也会生效。解决方案如下(如果不需要,请忽略didHighlightdidSelect方法):

(请注意,“被覆盖行”是我们要保持可见的行,而在我的情况下,其内容稍微延伸到上面的行中,从而导致它被裁剪)

-(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;
    }
}

注意:您还应该将内容的背景颜色设置为透明,否则它将采用单元格其余部分的背景颜色。因此当您将内容带到覆盖单元格的前面时,它将带走背景颜色并在其他单元格中留下不良的块(在我的情况下,我的唯一内容是detailTextLabeltextLabel):

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

我希望这对于其他尝试此方法的人有所帮助... 原文: 对我来说,解决方案是使用:
self.contentView.superview.clipsToBounds = NO;

我的单元格已经是透明的了,但我的内容仍然被裁剪。在我的情况下,我使用了一个自定义单元格,在layoutSubviews中向上移动其内容。因此,我的自定义单元格的layoutSubviews如下:

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

我不确定如果上面的单元格是不透明的,或者当按下单元格时单元格是否会高亮显示,这是否会覆盖我的内容。

然而,在viewWillDisplayCell回调方法中,我不需要再次使单元格透明 - 在普通的cellForRowAtIndexPath方法中这样做就足够了。


2

我遇到了这个问题,我确保我的自定义tableviewcell的主背景勾选了“剪裁子视图”,并解决了这个问题。虽然是从xib加载的自定义tableview cell,但不完全相同,但类似情况。


1

昨天我刚好遇到相反的情况,我创建了一个自定义表格单元,但出现了不想要的溢出。我的解决方法是在我的视图控制器类中添加以下代码:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{  
    return 175;
}

当它匹配表格单元格的高度时,就没有重叠;当它太小时就会重叠。不过请注意,我得到了非常快速的行为,所以我不确定这是否是一个好主意。


这会修改表格单元格的实际高度,而在我的情况下已经设置为45.0f(首选高度)。此外,修改它只会将单元格“向下”延伸,而我的问题存在于单元格顶部。 - NSSec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接