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

时间:2014-09-29 23:58:23

标签: ios objective-c uitableview autolayout

我似乎无法让AutoLayout在我的表视图单元格上工作。

在某些细胞上它似乎起作用,而在其他细胞上它似乎不起作用。甚至是完全相同类型的细胞。

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

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

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

我正在使用此StackOverflow问题来指导我的流程作为第一个定时器执行此操作: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请求添加更多信息 enter image description here

要明确,我提出了约束条件:

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

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

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

谢谢大家!

2 个答案:

答案 0 :(得分:3)

我还没有尝试过使用新的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来说还不够。每次调用UILabel时,我都必须继承preferredMaxLayoutWidth来更新layoutSubviews

preferredMaxLayoutWidth"修复"似乎是我失踪的神秘秘密。一旦我这样做,我的大多数细胞都能很好地工作。

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

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

修改

在iOS 8中遇到我自己的一些问题之后,我又添加了一些细节来解决这些奇怪的autoLayout错误。

根据我提到的代码,当单元格"行高"时,它似乎不起作用。未设置为自定义。通过选择单元格并单击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改变了苹果!

对于preferredMaxLayoutWidth的IB设置似乎存在问题,因为iOS 7无法使用自动功能,如果您在多个设备上使用相同的UILabel,它只会进行使用1宽度。因此,iOS 8平板电脑上的UITableViewCell会更大,因为相同的手机需要在iOS 8 iPhone上拥有2条线。

答案 1 :(得分:1)

这是我的尝试。

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

- (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中,但这应该是您需要的所有内容。快乐的编码。