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


104

我正在以编程方式使用自动布局约束来布局自定义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属性设置contentView为NO =>会弄乱整个单元格。

44是默认的单元格高度,但是我在表格视图委托中定义了我的自定义高度,那么为什么单元格contentView具有此约束?是什么原因造成的?

在iOS6中,这没有发生,并且在iOS6和iOS7上一切正常。

我的代码很大,所以我不会在这里发布它,但是如果您需要它,可以随时要求一个pastebin。

要指定我的操作方式,有关单元格初始化:

  • 我创建了所有标签,按钮等
  • 我将其translatesAutoresizingMaskIntoConstraints财产设置为“否”
  • 我将它们添加为contentView单元格的子视图
  • 我在 contentView

我也很想了解为什么仅在iOS7上会发生这种情况。


您的自定义单元格高度设置为什么?
Mike Pollard

我的自定义单元格高度设置为90
Alexis

一位同事昨天也遇到了同样的问题,但是默认宽度为320(对于iPad应用程序)。
jrturton

这里有一个示例项目演示了相同的问题:github.com/Alex311/TableCellWithAutoLayout 这是我对它的一些观察:github.com/Alex311/TableCellWithAutoLayout/commit/…–
smileyborg

我遇到了同样的错误,但这是因为我从未初始化过用来查找自定义单元格高度的额外原型单元格。
Steve Moser 2014年

Answers:


132

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

详细查看contentView之后,似乎不再设置autoresizingMask。

在约束视图之前设置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;
}

这项工作感谢了伙计。使用编辑样式时会发生什么?
亚历克西斯

11
@ L14M333请参阅我在此注释中发布的代码-基本上,您应该可以self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);在添加约束之前进行设置,这应该可以解决问题。
smileyborg

2
autoresizingMask对我不起作用:最初的约束消失了,但是添加了3个新的约束。 “ << NSAutoresizingMaskLayoutConstraint:0x8b7b9f0 h =-&-v =-&-UITableViewCellScrollView:0x8b4a130.height == LibraryCell:0x8ac19d0.height>”,“ << NSAutoresizingMaskLayoutConstraint:0x8b7c590 h =-&v =-&V:[Library 0x8ac19d0(0)]>“
卡他非他明2014年

1
我也一直在努力,为此我奋斗了大约一个小时!谢谢!<3
mokagio

2
摆脱了其他自动布局问题(iOS 7 / iOS 8)之后,我发现using的使用self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);效果与using 一样好self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;。我把这个updateConstraints增加的约束,我的内容视图之前。
测试了

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

由于静态表视图控制器易碎,如果实现某些数据源或deletegate方法,则很容易损坏-有检查将确保仅在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的想法都是相同的,就像在此线程中所评论的:仅在iOS 7上运行时,才会在Storyboard原型单元(Xcode 6,iOS 8 SDK)中自动调整UICollectionViewCell contentView框架的大小


1
这是最好的答案,或者至少对我来说是最佳解决方案。我的单元格(自动布局规则)在Xcode6的iOS8上运行良好,在XCode 5的iOS7和6上运行良好。我将XCode更新为XCode6,在iOS6和7上不再运行。所以,谢谢!!!
2014年

Xcode 6.1不再是问题。另外,请勿使用NSFoundationVersionNumber,请参阅nshipster.com/swift-system-version-checking
onmyway133

1
@ onmyway133:为什么在Xcode 6.1中这不再是问题?即使使用Xcode 6.1和iOS 8.1 SDK,我仍然有问题。仅在iOS 7上会出现此问题。更改边界或设置自动调整大小的遮罩可解决此问题。但是我使用了投票最多的答案或其评论中所述的方法。
测试时间

是的,根据我3个小时的谷歌搜索,这是最好的答案。其他类似的“解决方案”没有提供cell.contentView.autoresizingMask的完整列表。只有这一个作品我的iPad 7.1的项目在Xcode 6.创建
金拇指

13

随着单元被重用并且高度可以根据内容而变化,我认为通常最好将间距的优先级设置为小于要求的范围。

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

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


你是个天才!好的和干净的解决方案,谢谢:)
Blacky 2015年

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”
  • 右键单击情节提要
  • 打开为->界面生成器
  • 运行您的应用程序并检查输出

这对我有用。我在情节提要中创建了一个UITableViewController,其中一些单元是通过原型创建的,而某些则是通过原型创建的,而其他则完全是通过代码创建的。
Atharva 2015年

3

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


确实,我的单元格比默认大小高,但是自从表视图的委托实现tableView:heightForRowAtIndexPath:以来,如何使用默认大小呢?
亚历克西斯

可能会使用默认大小创建像元,然后将其调整为实际大小。
Vadim Yelagin

确实可以完成工作,但是为什么在iOS6上不发生呢?
亚历克西斯(Alexis)2013年

3
@jafar iOS 7改变了表视图单元格周围的许多内容。在iOS 7上,UITableViewCellScrollView表格视图单元格和contentView之间现在有一个滚动视图(类型为);这很可能在这里解释了iOS 6和iOS 7之间的区别。
smileyborg

3

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

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

2

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

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

最好,亚历山德罗


2
来自苹果公司的文档:You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
Ricardo Sanchez-Saez 2014年

我想开始一种宗教向你祈祷。我一直在寻找试图解决此问题的小时,并且可以解决此问题(以及将contentView.bounds设置为CGRectMake(0,0,99999,99999);)-这在苹果代码中是一个错误。因此,我尊重苹果文档所说的不调用该函数的观点。苹果,解决你的废话。
瑞安·科普利2015年

0

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


0

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


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"/>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.