iOS 7.1中,UITableView的单元格内容会与下面的单元格重叠。

31

我有一段代码,在iOS 7.0上成功运行,但在7.1上却无法工作。我有一个简单的表视图,其中包含以下代码:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

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

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

    for (UIView *view in cell.contentView.subviews) {
        [view removeFromSuperview];
    }

    UILabel *label = [[UILabel alloc] init];
    label.text = [NSString string];

    for (NSInteger i = 0; i < 20; i++) {
        label.text = [label.text stringByAppendingString:@"label String "];
    }

    label.translatesAutoresizingMaskIntoConstraints = NO;
    label.numberOfLines = 0;
    label.lineBreakMode = NSLineBreakByWorldWrapping;
    //label.lineBreakMode = NSLineBreakByTruncatingTail; //I have tried this too
    [cell.contentView addSubview:label];

    NSDictionary *dict = NSDictionaryOfVariableBindings(label);
    [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-8-[label]-8-|" options:0 metrics:nil views:dict]];
    [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[label]" options:0 metrics:nil views:dict]];

    if (indexPath.row == 0) {
        label.textColor = [UIColor colorWithRed:1.0 green:0 blue:0 alpha:1.0];
    }
    else if (indexPath.row == 1) {
        label.textColor = [UIColor colorWithRed:0 green:1.0 blue:0 alpha:1.0];
    }
    else if (indexPath.row == 2) {
        label.textColor = [UIColor colorWithRed:0 green:0 blue:1.0 alpha:1.0];
    }
    else {
        label.textColor = [UIColor colorWithWhite:0.3 alpha:1.0];
    }

    cell.backgroundColor = [UIColor colorWithWhite:1.0 alpha:1.0];
    return cell;
}

我有一个包含10行的1个section。每次重用一行时,我都会从contentView删除所有子视图(我尝试了alloc-init UITableViewCell,但结果相同)。

iOS 7.0中,UILabel仅在其所属的单元格中显示。但是在7.1中,UILabel继续显示在其他单元格上。有趣的是,当我点击单元格时,它停止被其他单元格覆盖,但只有当我点击上面的单元格时才会停止。我的问题是,如何使它在7.1设备上像7.0设备那样工作。

我尝试了模拟器和设备,并查看了iOS 7.1 API差异,但没有发现与此相关的内容。

也许这是自动布局的问题,因为UILabel具有可变高度,但我需要这样做。我希望在UILabel中包含所有文本,但仅显示可以在单元格中显示的UILabel的一部分,这是7.0中的默认行为,但7.1更改了此行为,我不知道原因以及如何处理它。

这是带有详细说明的图片的Dropbox文件夹:图片文件夹

更新:我尝试了像这样的东西,但对我没有用。

cell.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 70);
cell.contentView.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 70);

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

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

cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;
7个回答

67
问题与单元格的高度有关。它不会为您动态调整高度。
当您滚动并且上面的视图消失时,您可能会注意到重叠的文本也会消失。
如果您想要在特定高度处截断文本,则需要设置行数,而不是将其设置为0,因为这样会让它无限制地继续。
由于它没有停止,所以lineBreakMode不会生效。
可以选择在contentView上设置剪切,以确保所有子视图都留在内部。
根据您想要的最终结果,您可以进行动态高度并根据内容进行更改。有许多与此相关的SO问题。
更新 - 剪辑contentView
我必须自己尝试一下,但是在那之前,这里有几个与剪辑contentView相关的链接:

看起来这样可以工作:

cell.clipsToBounds = YES;

最终我找到了解决方案: cell.clipsToBounds = YES; 这解决了我的问题,并且在7.0和7.1上显示良好。不知道为什么我没有在文档中找到它现在是必要的,如果你想像我一样做的话。现在我看到了你的评论,我发现你提到了它,所以你可以回答并且我会标记它为已接受,或者我会自己做出答案。 - Matej Kosiarcik
如果您正在使用界面构建器构建单元格,则单元格本身上的“剪切子视图”(三个选项中的顶部)具有相同的效果。 - t0PPy
对我来说,这似乎是iOS 7.1的问题而不是7.0,那个版本工作正常。但我想7.0自动打开了剪辑。 - Nate Hat
太棒了,解决了我的问题并拯救了我的一天。非常感谢。 - Manann Sseth
花了一个小时来解决这个问题。最终终于解决了。非常感谢 Ryan。 - Pascal
显示剩余2条评论

7
以下是单元格中重叠内容的完美解决方案。
在分配单元格并添加子视图之前,只需在cellForRowAtIndexPath中使用以下代码即可。
for (id object in cell.contentView.subviews)
{
    [object removeFromSuperview];
}  

实际上,重叠发生的原因是每当您滚动tableview时,它会再次分配您添加的视图。因此,以上代码将通过从单元格的contentView中删除现有视图来解决您的问题。

现在,在应用上述代码后,您可以查看内存调试会话,这次您的内存是稳定的。

希望能对您有所帮助。

谢谢!


这不是我的问题。你描述的情况是当前cell0的视图与之前的cell0的视图重叠了。但问题是当前cell0的视图与当前cell1的视图重叠了。此外,我已经有了你建议的代码(尽管现在我更愿意将其放在prepareForReuse方法中)。 - Matej Kosiarcik

2
这是重新创建单元格内容的问题。请尝试以下代码段。
for(UIView *view in cell.contentView.subviews){  
        if ([view isKindOfClass:[UIView class]]) {  
            [view removeFromSuperview];   
        }
    }

当我编写这段代码时,单元格会显示出来,但是代码似乎没有删除旧的单元格,因为我在新单元格下面看到了旧值。 - Esqarrouth
你能看一下这个吗:http://stackoverflow.com/questions/27355545/swift-reuse-cells-in-ios7-1-simulator-cells-are-hidden - Esqarrouth

2

@Gaurav 你的回答应该被接受为正确答案。谢谢!

for object in cell.contentView.subviews
            {
                object.removeFromSuperview();
            }

1
很高兴我的回答有所帮助! - Gaurav Singla
我简直不敢相信!它成功了! - Stephan Januar

1
在iOS 8中,使用storyboard / IB也会出现类似的行为。解决方法是从底部视图到原型单元格的Content View添加一个“底部间距:父视图”约束。其他视图和约束都从顶部锚定。

0
重新检查所有4个约束条件是有帮助的。在使用表格视图或集合视图时,必须应用所有四个约束条件(leading、trailing、top、bottom)。

0
你正在使用storyboard吗? 如果是的话,在storyboard中选择表视图控制器,取消“下部栏”下方的复选框。 你也可以通过编程方式实现这个效果。
如果你的TVC继承自导航视图控制器或标签式视图控制器,则可能需要在父视图上取消此布局选项。

我尝试了一下,但好像没有任何作用。是的,我正在使用Storyboards,我的TableViewController属于NavigationController。我在两个上都取消了勾选,但什么也没发生。 - Matej Kosiarcik
哦,你可以尝试的另一件事是清理cellForRowAtIndexPath内部的代码。 我注意到如果在这段代码中放置循环或某些逻辑,事情会变得有点奇怪。 所以:将for循环移到外面(创建一个数组或其他东西以后读取),并可能将if / else语句更改为switch语句,看看是否有帮助。 - TooManyEduardos
尝试了两种方法,但都没有帮助。最终我找到了解决方案:cell.clipsToBounds = YES; 这解决了我的问题,并且在7.0和7.1上显示良好。不明白为什么我在文档中没有找到它现在是必需的,如果你像我一样想这样做。我会发布答案,但必须等待。 - Matej Kosiarcik
这对我也起作用了,将 clipsToBounds 设置为 YES。非常令人沮丧。 - ToddB

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