291

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-Encapsulated-Layout-Height是第一次渲染时计算出的单元格高度——(我将UITextView高度设置为> = 70.0)但是这个派生的约束随后推翻了一个更新用户 cnstraint。

更糟糕的是,虽然布局代码说它试图打破我的高度约束,但它没有——它继续重新计算单元格高度,一切都按照我的意愿绘制。

那么,什么是NSLayoutConstraint UIView-Encapsulated-Layout-Height(我猜它是自动调整单元格大小的计算高度),我应该如何强制它干净地重新计算?

4

20 回答 20

312

尝试将您的优先级降低_collapsedtextHeightConstraint到 999。这样系统提供的UIView-Encapsulated-Layout-Height约束总是优先。

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

另外:虽然系统提供的约束是否正确可能存在争议,但与框架抗争是没有意义的。只需接受系统约束优先。如果您认为系统约束是错误的,请确保从委托中返回正确的 rowHeight。

于 2014-09-11T19:43:01.953 回答
73

我有一个类似的场景:一个带有一个行单元格的表格视图,其中有几行 UILabel 对象。我正在使用 iOS 8 和自动布局。

当我旋转时,我得到了错误的系统计算行高(43.5 远小于实际高度)。看起来像:

"<NSLayoutConstraint:0x7bc2b2c0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7bc37f30(43.5)]>"

这不仅仅是一个警告。我的表格视图单元格的布局很糟糕 - 所有文本都重叠在一个文本行上。

令我惊讶的是,以下行神奇地“修复”了我的问题(自动布局没有任何抱怨,我在屏幕上得到了我所期望的):

myTableView.estimatedRowHeight = 2.0; // any number but 2.0 is the smallest one that works

有或没有这条线:

myTableView.rowHeight = UITableViewAutomaticDimension; // by itself this line only doesn't help fix my specific problem
于 2014-11-26T11:42:01.723 回答
39

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

发生这种情况是因为大多数开发人员通常使用固定高度或某种锚约束来在单元格/标题中布局元素。发生冲突是因为当第UITableView一次加载/布置时,它将其单元格的高度设置为 0。这显然与您自己的约束相冲突。要解决这个问题,只需将任何固定高度约束设置为较低的优先级 ( .defaultHigh)。仔细阅读控制台消息,看看布局系统决定打破哪个约束。通常这是需要更改其优先级的那个。您可以像这样更改优先级:

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

NSLayoutConstraint.activate([
            companyNameTopConstraint,
           the rest of your constraints here
            ])
于 2019-12-02T09:39:58.733 回答
34

通过在约束中的一个值上指定优先级,我能够让警告消失,警告消息说它必须打破(下图"Will attempt to recover by breaking constraint")。看来,只要我将优先级设置为大于49,警告就会消失。

对我来说,这意味着改变我的约束,警告说它试图打破:

@"V:|[contentLabel]-[quoteeLabel]|"

至:

@"V:|-0@500-[contentLabel]-[quoteeLabel]|"

事实上,我可以为该约束的任何元素添加优先级,它会起作用。哪一个似乎并不重要。我的单元格最终达到了正确的高度,并且不显示警告。Roger,以您的示例为例,尝试在高度值约束@500之后立即添加(例如)。388388@500

我不完全确定为什么会这样,但我做了一些调查。在NSLayoutPriority 枚举NSLayoutPriorityFittingSizeCompression中,优先级似乎是50。该优先级的文档说:

当您向视图发送 FittingSize 消息时,会计算足够大以容纳视图内容的最小尺寸。这是视图希望在该计算中尽可能小的优先级。这是相当低的。在这个优先级上进行约束通常是不合适的。你想要更高或更低。

引用消息的文档内容如下:fittingSize

满足它所持有的约束的视图的最小尺寸。(只读)

AppKit 将此属性设置为视图可用的最佳大小,考虑到它及其子视图所持有的所有约束,并满足使视图尽可能小的偏好。此属性中的大小值永远不会是负数。

我还没有深入研究,但这似乎与问题所在有关。

于 2014-11-21T20:23:34.643 回答
12

我能够通过删除cell.layoutIfNeeded()tableViewcellForRowAt方法中的虚假来解决此错误。

于 2018-07-10T00:51:12.830 回答
9

尝试重新加载单元格,而不是通知表视图更新其约束:

[tableView beginUpdates];

[_briefCell collapse:!_showFullBriefText];

[tableView reloadRowsAtIndexPaths:@[[tableView indexPathForCell:_briefCell]] withRowAnimation:UITableViewRowAnimationNone];

[tableView endUpdates];

UIView-Encapsulated-Layout-Height可能是表格视图在初始加载期间根据单元格当时的约束为单元格计算的高度。

于 2014-08-08T16:35:28.737 回答
6

另一种可能:

如果您使用自动布局计算单元格高度(contentView 的高度,大部分时间如下),并且如果您有 uitableview 分隔符,则需要添加分隔符高度,以便返回单元格高度。获得正确的高度后,您将不会收到自动布局警告。

- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell {
   [sizingCell setNeedsLayout];
   [sizingCell layoutIfNeeded];
   CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
   return size.height; // should + 1 here if my uitableviewseparatorstyle is not none

}
于 2014-10-16T17:46:48.950 回答
6

正如杰西在问题评论中提到的那样,这对我有用:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

仅供参考,iOS 10 中不会出现此问题。

于 2017-07-19T11:20:16.737 回答
5

使用 UITableViewAutomaticDimension 并更改单元格内视图的高度约束时出现此错误。

我终于发现这是由于约束常数值没有被四舍五入到最接近的整数。

let neededHeight = width / ratio // This is a CGFloat like 133.2353
constraintPictureHeight.constant = neededHeight // Causes constraint error
constraintPictureHeight.constant = ceil(neededHeight) // All good!
于 2018-11-26T20:20:46.373 回答
3

我在集合视图单元格中遇到了类似的问题。

我通过将链接到单元格底部的最终约束的优先级(从视图顶部到底部的链中的最后一个——这最终决定了它的高度)降低到 999 来解决它。

牢房的高度是正确的,警告消失了。

于 2019-11-27T21:27:04.447 回答
3

我有同样的问题。对我来说,错误是 0.5 像素。

2020-08-06 21:33:20.947369+0530 DemoNestedTableView[4181:384993] [LayoutConstraints] 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. 
(

        "<NSLayoutConstraint:0x600000a3abc0 UICollectionView:0x7fde0780c200.height == 326   (active)>",
        "<NSLayoutConstraint:0x600000a3ae40 V:|-(0)-[UICollectionView:0x7fde0780c200]   (active, names: '|':UITableViewCellContentView:0x7fde05e0cb10 )>",
        "<NSLayoutConstraint:0x600000a3af30 V:[UICollectionView:0x7fde0780c200]-(0)-|   (active, names: '|':UITableViewCellContentView:0x7fde05e0cb10 )>",
        "<NSLayoutConstraint:0x600000a2a4e0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fde05e0cb10.height == 326.5   (active)>"
    )

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600000a3abc0 UICollectionView:0x7fde0780c200.height == 326   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

所以只是添加了这个并且它起作用了。

self.tableView.separatorStyle = .none
于 2020-08-06T16:08:07.437 回答
1

调整文本视图以适合其内容,并将高度约束常量更新为结果高度,UIView-Encapsulated-Layout-Height为我修复了约束冲突,例如:

[self.textView sizeToFit];
self.textViewHeightConstraint.constant = self.textView.frame.size.height;
于 2014-10-01T13:23:09.150 回答
1

就我而言,问题在于 a 中的垂直UIStackView线UITableViewCell,它根据数据显示/隐藏行。我正在使用自动调整单元格大小,并且单元格本身始终正确显示,高度正确。只是日志中充满了关于UIView-Encapsulated-Layout-Height.

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

于 2021-02-18T09:30:09.010 回答
1

设置这个view.translatesAutoresizingMaskIntoConstraints = NO;应该可以解决这个问题。

于 2018-01-02T07:25:30.770 回答
1

在花了几个小时来解决这个错误之后,我终于找到了一个适合我的解决方案。我的主要问题是我为不同的单元格类型注册了多个笔尖,但是特别允许一种单元格类型具有不同的大小(并非该单元格的所有实例都将具有相同的大小)。因此,当 tableview 试图使该类型的单元格出列并且它恰好具有不同的高度时,就会出现问题。我通过设置解决了

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});

每当单元格有数据来计算其大小时。我想它可以在

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

就像是

cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});

希望这可以帮助!

于 2016-06-28T21:53:56.547 回答
1

没有人回答如何解决故事板中的案例。您有我的情况,top bottom constraint优先fixed height级为 1000。这就是为什么在第一次加载时,由于表格视图单元格高度为 0,尝试将元素设置为固定高度,从而导致约束冲突。(我试图在 0 像素高度区域中插入 40 像素,因此编译器尝试丢弃 40 像素高度)。一旦加载了tableview,它就不会生成(比如弹回tableview或切换tab bar tab)

因此将优先级从 更改required @1000High @750Low @250。第一次加载,不考虑较低的优先级,然后调整所有约束的大小layoutSubviews()

在此处输入图像描述

于 2020-07-29T15:41:53.740 回答
0

我收到这样的消息:

无法同时满足约束...
...
...
...
NSLayoutConstraint:0x7fe74bdf7e50 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fe75330c5c0(21.5)]
...
...
将尝试恢复打破约束 NSLayoutConstraint:0x7fe0f9b200c0 UITableViewCellContentView:0x7fe0f9b1e090.bottomMargin == UILabel:0x7fe0f9b1e970.bottom

我正在使用自定义UITableViewCell高度UITableViewAutomaticDimension。而且我也实现了这个estimatedHeightForRowAtIndex:方法。

给我带来问题的约束看起来像这样

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

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

[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-|。但是指定大小对我来说不是问题,它消除了日志,我不需要降低所需约束的优先级。

于 2016-03-11T17:22:34.317 回答
0

如果您UIView-Encapsulated-Layout-Height在带有 Xib/Storyboard 的调试控制台中出现警告。

你应该做这些事情:

  1. 转到Size Inspector页面
  2. 选中Row Height复选框Automatic。记录Row Height Value
  3. 设置tableView.estimatedRowHeightValue

没有更多警告⚠️

于 2021-03-26T10:27:09.747 回答
0

TableView 从委托获取 indexPath 处单元格的高度。然后从以下位置获取单元格cellForRowAtIndexPath

top (10@1000)
    cell
bottom (0@1000)

如果 cell.contentView.height:0 //<-> (UIView-Encapsulated-Layout-Height:0@1000) top(10@1000) 与 (UIView-Encapsulated-Layout-Height:0@1000) 冲突,

因为它们的优先级等于 1000。我们需要在UIView-Encapsulated-Layout-Height' 的优先级下设置最高优先级。

于 2015-11-06T03:55:59.543 回答
0

就我而言,我确实设法通过将 Xcode 抱怨的约束的优先级设置为 来消除警告750,但在删除并将其重新插入表中后,单元格仍然使用错误的高度。

问题来自这样一个事实,即对beginUpdates()and endUpdates()(在我进行删除和插入之间)方法的调用被封装在一个UIView.animate(withDuration:)动画块中,我想在更新表时控制动画的持续时间。删除对动画块的调用为我解决了这个问题。

于 2021-07-15T12:29:04.440 回答