ios - AutoLayout uitableviewcell in landscape and on iPad calculating height based on portrait iPhone

标签 ios objective-c uitableview autolayout uiinterfaceorientation

我正在学习/试验自动布局和 UITableViewCell。几天前我问了另一个问题,我回答了我自己的问题,我仍在使用相同的约束/代码。有关完整代码,请参见此处:AutoLayout multiline UILabel cutting off some text .

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

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

看起来像这样: enter image description here

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

更糟糕的是,我在 iPad 上运行时得到了相同的结果,甚至是纵向模式,这意味着我得到了 iPhone 的尺寸。据我所知,好像 systemLayoutSizeFittingSize 没有方向或设备的概念。

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

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

最佳答案

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

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

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

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

这是我使用的模式,它不需要在 View Controller 中操作单元格控件。它更加封装,但可以说更昂贵。

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

关于ios - AutoLayout uitableviewcell in landscape and on iPad calculating height based on portrait iPhone,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23496547/

相关文章:

iphone - 为什么这个 CGRectContainsPoint 会失败?

ios - [FIRApp configure] 是否在 iOS 上以 DEBUG 模式发送统计信息?

ios - SSZiparchive 简单解档

objective-c - 将两个 XIB 连接到一个 ViewController

swift - 无法将 UITableViewCell 中的单元格数据推送到新的 UITableViewController

iphone - TableView 更新 'NSInternalInconsistencyException',原因 : 'Invalid update: invalid number of rows?

ios - UICollectionViewCell 布局问题 iOS9

java - Swift 或 Objective C 中的 java ByteBuffer 等价于什么?

objective-c - 将 View 的 NSInteger 属性设置为 NSInteger?

iOS自定义按钮和像venmo一样的 ScrollView