iOS 8 中的表格视图单元格自动布局

Posted

技术标签:

【中文标题】iOS 8 中的表格视图单元格自动布局【英文标题】:Table View Cell AutoLayout in iOS8 【发布时间】:2014-09-29 23:58:23 【问题描述】:

我似乎无法在我的表格视图单元格上使用自动布局。

在某些单元格上似乎可以工作,而在其他单元格上似乎不起作用。甚至是完全相同类型的单元格。

例如,在某些单元格上,描述将超过 1 行的文本,并且可以正常工作...

...然而在其他单元格上,描述将超过 1 行的文本,但仅显示其中的 1 行,并带有一堆空白。

你能帮我弄清楚我遗漏了什么或做错了什么吗?谢谢!

作为新手,我正在使用这个 *** 问题来指导我的流程:Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

1.设置和添加约束

我相信这些在大多数情况下都运作良好。

2。确定唯一的表视图单元格重用标识符

我不完全确定是否需要担心这部分,因为我总会有标题、时间和描述。

适用于 iOS 8 - 自行调整大小的单元格 3. 启用行高估计

我将此添加到viewDidLoad

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 180.0;

更新:为每个 Acey 请求添加更多信息

为了清楚起见,我设置了约束:

标题:左 15,上 85,右 15 标题和时间之间的垂直间距,为 10 时间和描述之间的垂直间距,为 10 我 Cmd 单击了所有三个标签并添加了前沿和尾随 边缘 我在描述和表格视图单元格的底部之间固定了 20

更新 2:已解决 下面的答案效果很好,但任何额外的间距也是由于为单元格设置的高度太大,所以 Xcode 会自动添加额外的空间来填充单元格的高度,因为文本标签没有填满表格视图的整个高度细胞。

如果您遇到此问题并遇到同样的问题,请告诉我您是否有任何问题或需要任何帮助。

谢谢大家!

【问题讨论】:

如果您尝试仅针对 ios 8 及更高版本并且可以正确设置约束,则可以省略 tableView:heightForRowAtIndexPath: 方法。似乎您可能在创建约束时遇到问题。您可以在 IB 中从左侧发布单元格的所有约束的屏幕截图吗? (我只能假设这是您需要帮助的领域 - 您还没有真正提出任何具体问题)。 感谢您的回复!我在底部更新了我的问题,以显示您想要查看的屏幕截图。让我知道这是否是您正在寻找的东西。我的主要问题是,我试图让这个单元格根据内容调整大小,但它不起作用,所以你能帮我弄清楚我错过了什么吗?谢谢! @Acey 我发布的屏幕截图是否有助于使其更清晰?感谢您的帮助! @Reez :你关心它是否是自动布局吗?我经常使用单元格,并且在自动布局方面也遇到过问题,所以我只是让它们变成动态的(使用 self.view.bounds)。如果您不关心使用自动布局,我可以在下面发布答案 @Chris 当然没问题! 【参考方案1】:

我还没有尝试使用新的 iOS 8 机制。但是我在使用 iOS 6 / 7 时遇到了类似的问题。将应用程序更新到 iOS 8 后它仍然可以正常工作,所以也许旧方法仍然是最好的方法?

我在这里有一些我的代码示例: AutoLayout multiline UILabel cutting off some text

这里: AutoLayout uitableviewcell in landscape and on iPad calculating height based on portrait iPhone

长话短说,iOS 8 之前的方式涉及保留一个单元格的副本,仅用于计算 tableView:heightForRowAtIndexPath: 内部的高度。但这对于处理多行UILabel 是不够的。每次调用 layoutSubviews 时,我都必须继承 UILabel 以更新 preferredMaxLayoutWidth

preferredMaxLayoutWidth“修复”似乎是我错过的神奇秘密。一旦我这样做了,我的大部分细胞都可以正常工作。

第二个问题我只需要我正确设置内容压缩阻力和内容拥抱属性,因此例如告诉标签拥抱文本将意味着它不会扩展以填充空白,这将导致单元格收缩。

完成这两件事后,我的单元格现在可以处理任何字体大小或任何数量的文本,而无需任何凌乱的布局代码。这需要学习很多东西,但我确实认为它最终得到了回报,因为我的应用中有很多动态内容。

编辑

在使用 iOS 8 遇到一些我自己的问题后,我添加了更多细节来解决这些非常奇怪的 autoLayout 错误。

使用我提到的代码,当单元格“行高”未设置为自定义时,它似乎不起作用。通过选择单元格并单击自动布局选项卡(所有内容压缩阻力设置等都在其中),可以在 IB 中找到此设置。按下复选框,它将填充一个临时高度。

其次,在我的代码中,我保留了一个单元格的本地副本,然后在 heightForRowAtIndexPath: 方法中多次重复使用它。每次调用时,这似乎都会使单元格高度增加很多。我不得不通过调用重新初始化本地副本:

localCopy = [self.tableView dequeueReusableCellWithIdentifier:@"mycell"];

似乎新的 Xcode 6 / iOS 8 更改非常不向后兼容 iOS 7,而且管理方式似乎完全不同。

希望这会有所帮助。

编辑 2

看完这个问题:iOS AutoLayout multi-line UILabel

我遇到了 iOS 7 / iOS 8 自动布局支持的另一个问题!!!我正在为 iOS 8 覆盖 layoutSubviews 我还需要覆盖 setBounds 以在调用 super 后更新 preferredMaxLayoutWidth。 WTF 变苹果了!

似乎是IB中preferredMaxLayoutWidth的设置有问题,因为iOS 7不能使用自动功能,如果你在多个设备上使用相同的UILabel,它只会使用1宽度。因此,iOS 8 平板电脑上的UITableViewCell 会更大,因为在 iOS 8 iPhone 上,同一个单元格需要有 2 行。

【讨论】:

太棒了,感谢您的演练,将尝试实现它! @Reez 没问题,让我知道它是怎么回事,我关注那个赏金 ;-)【参考方案2】:

这是我的尝试。

您可以创建一个方法/函数,让您获得所需的单元格视图。像这样:

- (UIView *) getCellView 

    UIView *cellView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 0.0f)];
    cellView.tag = 1;
    cellView.backgroundColor = [UIColor clearColor];

    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(15.0f, 10.0f, 15.0f, 15.0f)]; //I assumed that was the size of your imageView;
    imgView.image = [UIImage imageNamed:@"whatever-your-image-is-called"];
    [cellView addSubview:imgView];

    CGFloat xPadding = 15.0f;
    CGFloat yPadding = 15.0f;
    UILabel *headlineLabel = [[UILabel alloc ]initWithFrame:CGRectMake(xPadding, 0.0f, self.view.frame.size.width - (xPadding*2), 0.0f)];
    headlineLabel.numberOfLines = 0;
    headlineLabel.text = @"Red Sox season fell apart after World Series title (The Associated Press)";
    [headlineLabel sizeToFit];
    CGRect hFrame = headlineLabel.frame;
    if(hFrame.size.width > self.view.frame.size.width - 31.0f)
        hFrame.size.width = self.view.frame.size.width - 30.0f;
    hFrame.origin.y = imgView.frame.size.height + yPadding;
    headlineLabel.frame = hFrame;

    UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(xPadding, 0.0f, self.view.frame.size.height-(xPadding*2), 0.0f)];
    timeLabel.text = @"4h";
    //timeLabel.numberOfLines = 0; //uncomment if it will wrap on multiple lines;
    [timeLabel sizeToFit];
    hFrame = timeLabel.frame;
    if(hFrame.size.width > self.view.frame.size.width - 31.0f)
        hFrame.size.width = self.view.frame.size.width - 30.0f;
    hFrame.origin.y = headlineLabel.frame.size.height + yPadding;
    timeLabel.frame = hFrame;

    UILabel *descriptLabel = [[UILabel alloc] initWithFrame:CGRectMake(xPadding, 0.0f, self.view.frame.size.height - (xPadding*2), 0.0f)];
    descriptLabel.text = @"Boston (AP) -- To Boston Red Sox manager John Farrel, it hardly seems possible that just 11 months ago his team was celebrating the World Series championship on the field at Fenway Park.";
    descriptLabel.numberOfLines = 0; //I would suggest something like 4 or 5 if the description string vary from 1 line to more than 5 lines.
    [descriptLabel sizeToFit];
    hFrame = descriptLabel.frame;
    if(hFrame.size.width > self.view.frame.size.width - 31.0f)
        hFrame.size.width = self.view.frame.size.width - 30.0f;
    hFrame.origin.y = timeLabel.frame.size.height + yPadding;
    descriptLabel.frame = hFrame;

    cellView.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, descriptLabel.frame.origin.y + descriptLabel.frame.size.height + 15.0f /*some padding*/);
    return cellView;

如果您使用的是 indexPath.row,您只需将方法名称更改为 - (UIView *)getCellView:(NSIndex) *indexPath,它应该可以正常工作。

然后在你的 heightForRowAtIndexPath 中你可以做

return [[self getCellView] frame].size.height;

return [[self getCellView:indexPath] frame].size.height

在您的 cellForRowAtIndexPath 中,您可以执行以下操作

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) 

    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.textLabel.text = @"";
    cell.detailTextLabel.text = @"";

[[cell viewWithTag:1] removeFromSuperview];
[cell addSubview:[self getCellView]; //or [cell addSubview:[self getCellView:indexPath]];
return cell;

希望这会有所帮助。让我知道是否有不清楚或不太有效的地方。您可能需要调整一些内容以适应您的使用情况,尤其是在 cellForRowAtIndexPath 中,但这或多或少应该是您开始所需的一切。编码愉快。

【讨论】:

感谢试一试! 你在用它来处理 iOS7 和 iOS8 吗?只是想知道,因为我只担心 iOS8(尽管我确信这显然适用于 iOS8) 适用于 iOS8 和 iOS7。对于像 iPhone 6 和 iPhone 6 Plus 这样的大手机,它们很可能需要更大的图像和更大的文本,我添加了一些具有文本/字体和矩形大小的全局变量,以动态适应特定设备。上面的代码应该处理任何字体大小,因为它使用 sizetofit。

以上是关于iOS 8 中的表格视图单元格自动布局的主要内容,如果未能解决你的问题,请参考以下文章

如何在自动布局中滑动表格视图单元格?

iOS 自动布局:表格视图单元格宽度 = 0

为啥表格视图单元格中的自动布局会导致表格的内容大小被错误地更改?

自动布局 - 在表格单元格中对齐视图

使用自动布局表格视图时如何增加表格视图单元格中的标签高度(取决于文本)?

如何使用自动布局来调整表格视图单元格中的视图大小?