AutoLayout uitableviewcell在风景和iPad上基于人像iPhone计算高度

Sim*_*lin 5 objective-c uitableview uiinterfaceorientation ios autolayout

我正在学习/试验autolayout和UITableViewCell's.我几天前问了另一个问题,我回答了我自己的问题,我仍在使用相同的约束/代码.有关完整代码,请参阅此处:AutoLayout多行UILabel切断一些文本.

要在内部缩短它heightForRowAtIndexPath我使用自定义的实例UITableViewCell来计算行需要的高度.这在肖像中工作systemLayoutSizeFittingSize得很完美,但是当我切换到横向模式时,返回的单元格高度就像是纵向一样.我打印出了contentView标签和标签的框架,似乎没有任何更新.

结果是约束迫使标签增长,留下大量的空白.标签以正确的宽度显示,在景观中它们按照我的预期布局,如果我硬编码单元格的高度,它就能完美地工作.

它看起来像这样: 在此输入图像描述

硬编码后(我希望它看起来像): 在此输入图像描述

更糟糕的是,我在iPad上运行时得到了相同的结果,甚至是肖像模式,这意味着我得到了iPhone尺寸.从我所看到的情况来看,似乎systemLayoutSizeFittingSize没有方向或设备的概念.

我试过假装frame细胞应该是,尝试旋转细胞,调用layoutSubviews,重新加载tableView方向改变,似乎没有任何影响它.

我错过了什么基本的东西?

Tom*_*ift 13

@rdelmar有正确的方法.在contentView上调用systemLayoutSizeFittingSize之前,您肯定需要重置每个标签上的preferredMaxLayoutWidth.我还使用了一个带有layoutSubviews方法的UILabel子类.

像这样的自动布局方法的主要缺点是开销.对于将要显示的每个单元格,我们有效地运行autolayout三次:一次为systemLayoutSizeFittingSize准备大小调整单元格(在每个子标签上调整大小并设置preferredMaxLayoutWidth),再次调用systemLayoutSizeFittingSize,再次在实际单元格上返回来自cellForRowAtIndexPath.

为什么我们需要/想要第一次自动布局通行证?没有它我们不知道将我们的子标签preferredMaxLayoutWidth值设置为什么宽度.我们可以在@rdelmars示例中对这些值进行硬编码(这很好),但是如果更改单元格布局或者需要处理大量单元格类型,它会更加脆弱.

如果主要问题是在方向更改时重新计算,那么下面的代码可能会被优化,以便每次方向更改只运行一次布局.

这是我使用的模式,它无需在视图控制器中操作单元格控件.它更封装,但可能更昂贵.

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // assumes all cells are of the same type!
    static UITableViewCell* cell;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        cell = [tableView dequeueReusableCellWithIdentifier: @"label_cell"];
    });

    // size the cell for the current orientation.  assume's we're full screen width:
    cell.frame = CGRectMake(0, 0, tableView.bounds.size.width, cell.frame.size.height );

    // perform a cell layout - this runs autolayout and also updates any preferredMaxLayoutWidths via layoutSubviews in our subclassed UILabels
    [cell layoutIfNeeded];

    // finally calculate the required height:
    CGSize s = [cell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];

    return s.height + 1; // +1 because the contentView is 1pt shorter than the cell itself when there's a separator.  If no separator you shouldn't need +1
}
Run Code Online (Sandbox Code Playgroud)

随着:

@interface TSLabel : UILabel
@end

@implementation TSLabel

- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
    [super layoutSubviews];
}

@end
Run Code Online (Sandbox Code Playgroud)