105

I'm using auto layout constraints programmatically to layout my custom UITableView cells and I'm correctly defining the cell sizes in tableView:heightForRowAtIndexPath:

It's working just fine on iOS6 and it does look fine in iOS7 as well

BUT when I run the app on iOS7, here's the kind of message I see in the console:

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2013-10-02 09:56:44.847 Vente-Exclusive[76306:a0b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

And indeed there's one of the constraint in that list I don't want :

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

and I cannot set the translatesAutoresizingMaskIntoConstraints property of the contentView to NO => it would mess up the entire cell.

44 is the default cell height but I defined my custom heights in the table view delegate so why does the cell contentView has this constraint? What could cause this?

In iOS6 it's not happening and everything looks just fine on both iOS6 and iOS7.

My code is quite big so I won't post it here but feel free to ask for a pastebin if you need it.

To specify how I'm doing it, on cell intialization:

  • I create all my labels, buttons, etc
  • I set their translatesAutoresizingMaskIntoConstraints property to NO
  • I add them as subviews of the contentView of the cell
  • I add the constraints on the contentView

I'm also deeply interested in understanding why this happens only on iOS7.

4

10 回答 10

133

layoutSubviews我也遇到了这个问题。看起来 contentView 的框架在被调用之前不会更新, 但是单元格的框架会更早更新,而 contentView 的框架会{0, 0, 320, 44}在评估约束时设置为。

在更详细地查看 contentView 之后,似乎不再设置 autoresizingMasks。

在约束视图之前设置 autoresizingMask 可以解决此问题:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}

斯威夫特5,ios14:

contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
于 2013-10-03T08:24:44.297 回答
35

显然,使用 iOS 8 SDK 在 iOS 7 上的 UITableViewCell 和 UICollectionViewCell 有问题。

当单元格被重用时,您可以更新单元格的 contentView,如下所示:

对于静态 UITableViewController:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

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

    //your code goes here

    return cell;
}

#endif
#endif

由于静态表视图控制器很脆弱,如果您实现一些数据源或删除门方法很容易被破坏 - 有一些检查将确保此代码只能在 iOS 7 上编译和运行

标准动态 UITableViewController 类似:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

对于这种情况,我们不需要编译额外检查,因为需要实现此方法。

这两种情况和 UICollectionViewCell 的想法都是相同的,就像在这个线程中评论的那样:Autoresizing issue of UICollectionViewCell contentView's frame in Storyboard prototype cell (Xcode 6, iOS 8 SDK) occur when running only on iOS 7

于 2014-09-17T08:50:13.980 回答
13

由于单元格被重用并且高度可以根据内容而改变,我认为一般来说最好将间距的优先级设置为小于要求的值。

在您的情况下, UIImageView 与顶部的间距为 15,底部视图与底部的间距为 0。如果您将这些约束的优先级设置为 999(而不是 1000),则应用不会崩溃,因为这些约束不是必需的。

一旦调用了 layoutSubviews 方法,单元格将具有正确的高度,并且可以正常满足约束。

于 2014-08-01T10:28:22.730 回答
9

我仍然没有找到故事板的好解决方案......这里还有一些信息: https ://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

根据他们的建议:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

我已经提出了我的解决方案:

  • 右键单击故事板
  • 打开为 -> 源代码
  • 在那里搜索字符串“44”
  • 它会像

.

<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
        <rect key="frame" x="0.0" y="22" width="320" height="44"/>

.

  • 将 rowHeight="44" 替换为 rowHeight="9999" 和 height="44" 替换为 height="9999"
  • 右键单击故事板
  • 打开为 -> 界面生成器
  • 运行您的应用程序并检查输出
于 2014-01-12T08:27:45.603 回答
3

只需增加默认单元格高度即可。看起来问题在于单元格的内容大于默认(初始)单元格大小,违反了一些非负约束,直到将单元格调整为实际大小。

于 2013-10-02T11:36:16.253 回答
3

也许将视图的优先级设置为大于 750 小于 1000 可以解决。

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
于 2015-06-19T07:47:34.293 回答
2

我有同样的问题。我的解决方案基于上述其他人:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // initialize my stuff
        [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
    }
    return self;
}

最好的,亚历山德罗

于 2014-04-02T12:18:03.783 回答
0

我也遇到过这个问题,没有任何建议有帮助。在我的情况下,我有大小选择单元格,它在里面包含 collectionView(每个 collectionView 单元格都包含全尺寸图像)。现在,单元格大小高度 (60) 比 collectionView (50) 和其中的图像 (50) 大一点。因为collectionView视图的底部与superview约束对齐,值为10。这种情况下我会发出警告,解决这个问题的唯一方法是使单元格高度与其collectionView相同。

于 2014-05-27T13:30:00.533 回答
0

我最终没有在设计器中使用 UITableViewCell ...我在那里创建自定义视图并以编程方式将其添加到单元格的内容视图中...使用一些帮助类别也没有代码样板...

于 2015-01-06T08:25:04.047 回答
0

如果它在 iOS8 中运行良好,并且在 iOS7 中得到警告,您可以搜索故事板源代码,找到正确的 tableviewCell,然后在 tableviewCell 行后面附加 rect 属性。感谢kuchumovn

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
于 2015-06-04T08:31:07.703 回答