AutoLayout uitableviewcell 在横向和 iPad 上基于纵向 iPhone 计算高度 [英] AutoLayout uitableviewcell in landscape and on iPad calculating height based on portrait iPhone

查看:14
本文介绍了AutoLayout uitableviewcell 在横向和 iPad 上基于纵向 iPhone 计算高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm learning / experimenting with autolayout and UITableViewCell's. I asked another question a few days ago to which I answered my own question, I'm still using the same constraints / code. For the full code see here: AutoLayout multiline UILabel cutting off some text .

为了在 heightForRowAtIndexPath 内缩短它,我使用自定义 UITableViewCell 的实例来计算行需要的高度.这在纵向上非常有效,但是当我切换到横向模式时,systemLayoutSizeFittingSize 将返回与纵向相同的单元格高度.我已打印出 contentView 的框架和标签,但似乎没有任何更新.

To cut it short inside heightForRowAtIndexPath I am using an instance of a custom UITableViewCell to calculate the height the row needs to be. This works perfect in portrait, however when I switch to landscape mode, systemLayoutSizeFittingSize is returning the same height for the cell as if it was in portrait. I've printed out the frames of the contentView and the labels and nothing seems to be updating.

这样做的结果是约束迫使标签增长,留下大量空白.标签以正确的宽度显示,横向布局,如我所料,如果我硬编码单元格的高度,它可以完美地工作.

The result of this is the constraints are forcing the labels to grow leaving a huge amount of whitespace. The labels display in the correct width, in landscape they are laid out as I would expect, If I hardcode the height of the cell it works perfectly.

看起来像这样:

硬编码后(我希望它看起来像什么):

After hardcoding (what I want it to look like):

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

Even worse I get the same result when running on iPad, even portrait mode, meaning I get the iPhone dimensions. From what I'm seeing it is as though systemLayoutSizeFittingSize has no concept of orientation or device for that matter.

我尝试伪造单元格应该的 frame,尝试旋转单元格,调用 layoutSubviews,在方向更改时重新加载 tableView似乎没有任何影响.

I've tried faking the frame the cell should be, tried rotating the cell, calling layoutSubviews, reloading the tableView on orientation change and nothing seems to affect it.

我错过了一些基本的东西吗?

Have I missed something basic ?

推荐答案

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

@rdelmar has the right approach. You definitely need to reset the preferredMaxLayoutWidth on each label before you call systemLayoutSizeFittingSize on the contentView. I also use a UILabel subclass with the layoutSubviews method as he demonstrates.

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

The main downside to an autolayout approach like this is the overhead. We're effectively running autolayout three times for each cell that will be displayed: Once to prepare the sizing cell for systemLayoutSizeFittingSize (size it and set preferredMaxLayoutWidth on each sublabel), again with the call to systemLayoutSizeFittingSize, and again on the actual cell we return from cellForRowAtIndexPath.

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

Why do we need/want the first autolayout pass? Without it we don't know what width to set our child labels preferredMaxLayoutWidth values to. We could hardcode the values as in @rdelmars example (which is fine) but it's more fragile if you change your cell layout or have lots of cell types to deal with.

如果主要问题是重新计算方向变化,那么下面的代码可能会被优化为每次方向变化只运行第一次布局传递.

If the main issue is recalculating on orientation change then the code below can likely be optimized to run the first layout pass just once per orientation change.

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

Here's the pattern I use, which negates the need to manipulate the cell controls in the view controller. It's more encapsulated but arguably more expensive.

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

还有:

@interface TSLabel : UILabel
@end

@implementation TSLabel

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

@end

这篇关于AutoLayout uitableviewcell 在横向和 iPad 上基于纵向 iPhone 计算高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆