UITableViewCell中iOS7上的自动布局约束问题

时间:2013-10-02 08:30:14

标签: ios ios7 uitableview autolayout nslayoutconstraint

我正在以编程方式使用自动布局约束来布局我的自定义UITableView单元格,并且我正确地在tableView:heightForRowAtIndexPath:

中定义单元格大小

它在iOS6上工作正常,并且在iOS7中看起来也很好

但是当我在iOS7上运行应用程序时,这是我在控制台中看到的那种消息:

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

确实我不想要的那个列表中有一个约束:

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

我无法将translatesAutoresizingMaskIntoConstraints的{​​{1}}属性设置为NO =&gt;它会弄乱整个细胞。

44是默认的单元格高度,但我在表视图委托中定义了自定义高度,为什么单元格contentView有这个约束?什么可能导致这个?

在iOS6中它没有发生,iOS6和iOS7上的一切看起来都很好。

我的代码很大,所以我不会在这里发布,但如果你需要,可以随意索取一个pastebin。

要指定我是如何做的,请参阅单元初始化:

  • 我创建了所有标签,按钮等
  • 我将contentView属性设置为NO
  • 我将它们添加为单元格translatesAutoresizingMaskIntoConstraints的子视图
  • 我在contentView
  • 上添加了约束

我也非常有兴趣了解为什么只在iOS7上发生这种情况。

10 个答案:

答案 0 :(得分:132)

我也有这个问题..看起来,在调用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;
}

答案 1 :(得分: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) happens when running on iOS 7 only

答案 2 :(得分:13)

当细胞被重复使用并且高度可以根据内容而改变时,我认为通常最好将间距的优先级设置为低于要求。

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

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

答案 3 :(得分:9)

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

根据他们的建议:

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

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

  • 右键单击故事板
  • Open As - &gt;源代码
  • 在那里搜索字符串“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”
  • 右键单击故事板
  • Open As - &gt; Interface Builder
  • 运行您的应用并检查输出

答案 4 :(得分:3)

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

答案 5 :(得分:3)

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

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",

答案 6 :(得分:1)

我遇到了同样的问题。我的解决方案基于以上其他人:

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

最佳, 的Alessandro

答案 7 :(得分:0)

我也遇到了这个问题,没有一个建议有帮助。在我的情况下,我有大小选择单元格,它包含collectionView内部(每个collectionView单元格包含完整大小的图像)。现在,单元格大小的高度(60)比collectionView(50)和它内部的图像(50)大一点。因为collectionView视图已将底部与superview约束对齐,值为10.这种情况我是一个警告,解决这个问题的唯一方法是使单元格高度与其collectionView相同。

答案 8 :(得分:0)

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

答案 9 :(得分: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"/>