我有一个UITableView在iOS 8下运行,我在故事板中使用约束的自动单元格高度。

我的一个单元格包含一个UITextView,我需要它根据用户输入收缩和展开-点击收缩/展开文本。

我通过在文本视图中添加一个运行时约束,并在响应用户事件时改变约束上的常数来做到这一点:

-(void)collapse:(BOOL)collapse; {

    _collapsed = collapse;

    if(collapse)
        [_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0
    else
        [_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]];

    [self setNeedsUpdateConstraints];

}

无论何时我这样做,我包装在tableView更新和调用[tableView setNeedsUpdateConstraints]:

[tableView beginUpdates];

[_briefCell collapse:!_showFullBriefText];

[tableView setNeedsUpdateConstraints];
// I have also tried 
// [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
// with exactly the same results.

[tableView endUpdates];

当我这样做的时候,我的单元格确实会扩展(并在做的时候动画),但我得到一个约束警告:

2014-07-31 13:29:51.792 OneFlatEarth[5505:730175] 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:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>",

    "<NSLayoutConstraint:0x7f94dced2260 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...']-(15)-|   (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",

    "<NSLayoutConstraint:0x7f94dced2350 V:|-(6)-[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...']   (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",

    "<NSLayoutConstraint:0x7f94dced6480 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f94de5773a0(91)]>"
 )

Will attempt to recover by breaking constraint 

<NSLayoutConstraint:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>

388是我计算的高度,UITextView上的其他约束是我从Xcode/IB中得到的。

最后一个是困扰我-我猜uiview - encapsulation - layout - height是计算单元格的高度时,它是第一次渲染-(我设置我的UITextView高度>= 70.0),但它似乎不正确,这个派生约束然后驳回更新用户cnstraint。

更糟糕的是,尽管布局代码说它试图打破我的高度限制,但它并没有-它继续重新计算单元格的高度,一切都按照我想要的方式绘制。

所以,什么是NSLayoutConstraint UIView-Encapsulated-Layout-Height(我猜它是计算的高度自动单元格大小),我应该如何去迫使它重新计算干净?


当前回答

格瓦拉的回答让我走上了正确的道路。我已经在我的UITableViewCell中创建了一个高度约束的出口,并且我在运行时基于一些条件改变了这个高度约束。

而不是这个——

myHeightConstraint.constant = 0.0

我写道——

myHeightConstraint.constant = CGFloat.zero

这为我解决了这个警告。基本上,hightforrowat方法中返回的任何高度都应该与运行时使用约束计算的高度相同。

其他回答

我能够解决这个错误通过删除一个假cell.layoutIfNeeded(),我在我的tableView的cellForRowAt方法。

99.9%的情况下,当使用自定义单元格或标头时,UITableViews的所有冲突都发生在表第一次加载时。一旦加载,你通常不会再看到冲突。

This happens because most developers typically use a fixed height or anchor constraint of some sort to layout an element in the cell/header. The conflict occurs because when the UITableView first loads/being laid out, it sets the height of its cells to 0. This obviously conflicts with your own constraints. To solve this, simply set any fixed height constraints to a lower priority (.defaultHigh). Read carefully the console message and see which constraint the layout system decided to break. Usually this is the one that needs its priority changed. You can change the priority like this:

let companyNameTopConstraint = companyNameLabel.topAnchor.constraint(equalTo: companyImageView.bottomAnchor, constant: 15)
    companyNameTopConstraint.priority = .defaultHigh

NSLayoutConstraint.activate([
            companyNameTopConstraint,
           the rest of your constraints here
            ])

我收到的信息是这样的:

无法同时满足约束条件… ... ... ... NSLayoutConstraint: 0 x7fe74bdf7e50 UIView-Encapsulated-Layout-Height” V: [UITableViewCellContentView: 0 x7fe75330c5c0 (21.5)] ... ... 会试图通过打破约束来恢复吗 x7fe0f9b1e090 NSLayoutConstraint: 0 x7fe0f9b200c0 UITableViewCellContentView: 0。bottomMargin == UILabel:0x7fe0f9b1e970.bottom

我使用一个自定义的UITableViewCell和UITableViewAutomaticDimension的高度。我还实现了estimatedhighightforrowatindex:方法。

给我带来问题的约束条件是这样的

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[title]-|" options:0 metrics:nil views:views];

将约束改为this将解决问题,但就像另一个答案一样,我觉得这是不正确的,因为它降低了我希望被要求的约束的优先级:

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6@999-[title]-6@999-|" options:0 metrics:nil views:views];

然而,我注意到的是,如果我实际上只是删除优先级,这也是有效的,我不会得到破坏约束日志:

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6-[title]-6-|" options:0 metrics:nil views:views];

|-6-[title]-6-|和|-[title-|之间的区别是什么,这有点神秘。但是,指定大小对我来说不是问题,它消除了日志,而且我不需要降低所需约束的优先级。

在我的案例中,问题是UITableViewCell中的垂直UIStackView,这是基于数据显示/隐藏行。我使用自动调整单元格大小,单元格本身总是显示正确,具有正确的高度。只是日志中充满了关于uiview - encapsulation - layout - height的约束异常。

我通过为UIStackView的顶部和底部约束设置一个较低的优先级来解决这个问题(999而不是默认的1000)。现在没有约束异常,并且表的外观和行为完全相同。

试着降低你的_collapsedtextHeightConstraint的优先级到999。这样,系统提供的uiview - encapsulation - layout - height约束总是优先的。

它基于你在-tableView: highightforrowatindexpath:中返回的内容。确保返回正确的值和你自己的约束,生成的值应该是相同的。您自己的约束的较低优先级只是暂时需要,以防止折叠/展开动画运行时发生冲突。

补充:虽然系统提供的约束是否正确是有争议的,但与框架争论是没有意义的。简单地接受系统约束优先。如果您认为系统约束是错误的,请确保从委托返回正确的rowHeight。