iOS 7 和 iOS 8 中动态 UITableViewCell 的高度是不可能的

Posted

技术标签:

【中文标题】iOS 7 和 iOS 8 中动态 UITableViewCell 的高度是不可能的【英文标题】:Dynamic UITableViewCell's height in iOS 7 AND iOS 8 impossible 【发布时间】:2014-11-25 16:09:39 【问题描述】:

我很难尝试在 ios 7 和 8 下获得具有动态大小的单元格的表格视图。我无法详细说明要找到的所有差异(以“方式iOS 7 和 8 之间的损坏布局”),可以使用不同的“调整”、“解决方法”以及我在这里和其他地方找到的任何东西来生成。但最终在 iOS 7 或 iOS 8(如果不是两者)上,部分或全部单元格的内容未对齐,因为布局系统“打破”了“恢复”的自定义约束之一。

基本上我有三种不同类型的内容。由于我不仅在上述表格视图中显示这些内容,我还将这些内容包装在UIView 的三个子类中。让我们叫他们SummaryViews 对于表格视图,然后我创建了UITableViewCell 的三个子类,每个子类都将相应的SummaryView 添加到其contentView 并设置self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight。在updateViewConstraints 上,我通常会删除之前可能已添加的所有“我的”约束并执行...

- (void)updateConstraints

   // ...removed custom constraints before
    NSDictionary *views = NSDictionaryOfVariableBindings(_summaryView);

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_summaryView]-|"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:views]
                        toView:self.contentView];

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_summaryView]-|"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:views]
                        toView:self.contentView];
    [super updateConstraints];

tableView:estimatedHeightForRowAtIndexPath: 中,我根据内容的类型返回一个静态估计值。 在tableView:heightForRowAtIndexPath: 中,我以...的方式使用“原型”单元格。

// ..set content on prototype cell before
[prototypeCell setNeedsUpdateConstraints];
[prototypeCell layoutIfNeeded];
CGSize size = [prototypeCell systemLayoutSizeFittingSize:UILayoutFittingExpandedSize];
return size.height;

这里调试器通常在UIViewAlertForUnsatisfiableConstraints[prototypeCell layoutIfNeeded])上中断,<NSLayoutConstraint:0x17409f180 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x17019f070(44)]> 与其余约束冲突。

所以我尝试了...

在表视图的viewDidLoad 中设置tableView.rowHeight = UITableViewAutomaticDimension 未实现tableView:estimatedHeightForRowAtIndexPath:

使用...

if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) 
    cell.contentView.frame = cell.bounds;
    cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;

...在应用单元格的内容并计算其布局之前

在单元初始化时执行self.contentView.bounds = CGRectMake(0.0, 0.0, 1000, 1000); 可能还有其他事情,我现在不记得了,因为我现在差不多两天了。

总是一样的,如果我实现了一个不抱怨不可满足的约束的变体,那么布局通常还是一团糟。虽然我让表格视图不设置“默认”&lt;NSLayoutConstraint:0x17409f180 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x17019f070(44)]&gt; 约束,但设置的约束(基于tableView:heightForRowAtIndexPath: 返回的高度)既不适合布局系统。

这篇文章是最后的手段。我知道如果没有具体视图类的约束,您将无法重新检查它们。但由于我可以在表视图之外毫无问题地使用这些视图,所以它不应该是子视图的约束问题。

我想我将不得不手动计算所有视图元素的大小(基于[UIScreen mainScreen].bounds)并将它们直接设置(作为宽度和高度)到所有子视图。所以我可以得到一个单元格的具体高度,并且可以手动设置contentView 的框架。很可惜,因为它显着地弄乱了布局代码......

最好的问候, 加布里埃尔

【问题讨论】:

您走错了路,您的单元格的高度基于您通过–tableView:heightForRowAtIndexPath: 方法返回的值。这将定义屏幕上的实际高度。玩弄自动布局或自动调整大小蒙版无济于事。 @holex 你的狩猎声望? A:请随意告诉我(和其他人)什么是正确路径。 B:我认为tableView:heightForRowAtIndexPath 的用途从未有过任何疑问。 C:我不是玩弄自动布局,我实际上是在使用它。 D:与autoresizingMask玩耍似乎帮助了其他人:***.com/a/19154287/981728。 【参考方案1】:

最后我找到了一个可以接受的解决方案,它不会过多地弄乱布局代码。 简而言之:

在表格视图单元格的updateConstraints 中,我将约束从_summaryView-bottom 删除到superview-bottom。因此,内容视图的高度限制不会干扰摘要视图中的高度限制。

- (void)updateConstraints

    NSDictionary *views = NSDictionaryOfVariableBindings(_summaryView);

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_summaryView]-|"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:views]
                        toView:self.contentView];

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_summaryView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:views]
                        toView:self.contentView];
    [super updateConstraints];

tableView:heightForRowAtIndexPath: 中,我只使用相关单元格的intrinsicContentSize 来获取高度:

        [prototypeCell.summaryView applyStuff];
        [prototypeCell layoutIfNeeded];
        height = [prototypeCell intrinsicContentSize].height;

上述表格视图单元intrinsicContentSize的实现如下:

- (CGSize)intrinsicContentSize

    // Calculate the available content width if not done yet
    static CGFloat availableWidth = 0.0;
    if (availableWidth == 0.0) 
        availableWidth = CGRectGetWidth([UIScreen mainScreen].bounds);
    

    // Check if the contentView's frame needs an update
    if (CGRectGetWidth(self.contentView.frame) != availableWidth) 
        CGRect frame = CGRectMake(0.0, 0.0, availableWidth, 100.0);
        self.contentView.frame = frame;
    

    [_summaryView layoutIfNeeded];
    CGSize size = _summaryView.frame.size;
    size.height += 2.0 * V_PADDING;
    size.width += 2.0 * H_PADDING;
    return size;

请注意,对于支持纵向和横向模式的应用,availableWidth 必须在方向更改时重置,或者不应为static。 *_PADDING 是我希望_summaryView 在所有方面都有的空间。

我还从单元的初始化代码中删除了self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth。因为它似乎没有任何明显的效果。

【讨论】:

我感到你很沮丧,我正在使用类似的方法:不设置尾随约束,并通过将 self.view.frame.width (tableViewCell 由于UIView-Encapsulated-Layout-Width) 应用到子视图的框架来计算它的高度......希望看看有没有人能想出一种方法让contentView框架完全由intrinsicContentSize计算,似乎仍然没有可能的解决方案。 我的tableView单元格有一个很大的UILabel,在tableView:heightForRowAtIndexPath:,我使用contentLabelHeight = contentLabel.font.sizeOfString(contentLabel.text!, constrainedToWidth: Double(self.view.frame.width - 44)).height先计算高度(第44页是你的2.0 * H_PADDING)然后返回contentLabelHeight + contentLabel.frame .origin.y + 20(p.s. 20 是你的2.0 * V_PADDING 是的,iOS 7 下似乎没有 nice 处理“动态行高”的方法。【参考方案2】:

我可能在讨论中来晚了一点,但我遇到了类似的问题并找到了解决方案。

添加约束时,将它们添加到 contentView 而不是单元格。否则,“|-”和“-|”在视觉语言格式中会创建与单元格本身相关的约束,而我们糟糕的 contentView 将没有任何约束。

所以,不要使用[self addConstraints: ...];,而是使用[self.contentView addConstraints: ...];

【讨论】:

_summaryView 是单元格的contentView 的子视图。向视图添加约束时,约束是指这个视图还是它的子视图并不重要。 我刚刚仔细检查以确保它是否有所不同(在我当前的项目中)——确实如此。任何带有“|-”或“-|”的视觉语言约束指接收 addConstraint 方法的容器。我还收到消息“检测到约束模糊地建议 tableview 单元格的内容视图高度为零的情况”,如果我将“addConstraint”发送到 contentView 而不是单元格,我不会收到消息。 iOS8.3下。 好吧,这将是一个解释。遗憾的是,我目前没有时间用我们的项目进行测试。但我会记住的,迟早我会检查的......

以上是关于iOS 7 和 iOS 8 中动态 UITableViewCell 的高度是不可能的的主要内容,如果未能解决你的问题,请参考以下文章

在 IOS 8 中工作的具有动态高度的 UITableView 行在 ios 7 中不工作

使用 IOS9 时,无法在 UITable 的部分标题上的 UIButtons 上触发触摸事件(IOS10 很好)

iOS 8 中的 UITableViewCell 约束在 iOS7 中不起作用

UIButton 在 iOS 7 中无法正常工作

奇怪的 iOS 8 自动布局问题

iOS 8是否支持动态链接?