ios 什么是 NSLayoutConstraint“UIView-Encapsulated-Layout-Height”,我应该如何强制它干净利落地重新计算?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25059443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is NSLayoutConstraint "UIView-Encapsulated-Layout-Height" and how should I go about forcing it to recalculate cleanly?
提问by Rog
I have a UITableView
running under iOS 8 and I'm using automatic cell heights from constraints in a storyboard.
我UITableView
在 iOS 8 下运行,并且我正在使用故事板中约束的自动单元格高度。
One of my cells contains a single UITextView
and I need it to contract and expand based on user input - tap to shrink/expand the text.
我的一个单元格包含一个UITextView
,我需要它根据用户输入收缩和扩展 - 点击以缩小/扩展文本。
I'm doing this by adding a runtime constraint to the text view and changing the constant on the constraint in response to user events:
我这样做是通过向文本视图添加运行时约束并更改约束上的常量以响应用户事件:
-(void)collapse:(BOOL)collapse; {
_collapsed = collapse;
if(collapse)
[_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0
else
[_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]];
[self setNeedsUpdateConstraints];
}
Whenver I do this, I wrap it in tableView
updates and call [tableView 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];
When I do this, my cell does expand (and animates whilst doing it) but I get a constraints warning:
当我这样做时,我的单元格会扩展(并在执行此操作时进行动画处理)但我收到一个约束警告:
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 is my calculated height, the other constraints on the UITextView
are mine from Xcode/IB.
388 是我计算的高度,其他限制UITextView
来自 Xcode/IB。
The final one is bothering me - I'm guessing that UIView-Encapsulated-Layout-Height
is the calculated height of the cell when it is first rendered - (I set my UITextView
height to be >= 70.0) however it doesn't seem right that this derived constraint then overrules an updated user cnstraint.
最后一个困扰着我 - 我猜UIView-Encapsulated-Layout-Height
这是第一次渲染时计算的单元格高度 - (我将UITextView
高度设置为> = 70.0)但是这个派生约束然后推翻一个似乎不正确更新了用户 cnstraint。
Worse, although the layout code says it's trying to break my height constraint, it doesn't - it goes on to recalculate the cell height and everything draws as I would like.
更糟糕的是,虽然布局代码说它试图打破我的高度约束,但它没有 - 它继续重新计算单元格高度,一切都按照我的意愿绘制。
So, what is NSLayoutConstraint
UIView-Encapsulated-Layout-Height
(I'm guessing it is the calculated height for automatic cell sizing) and how should I go about forcing it to recalculate cleanly?
那么,什么是NSLayoutConstraint
UIView-Encapsulated-Layout-Height
(我猜它是自动单元格大小的计算高度),我应该如何强制它干净利落地重新计算?
回答by Ortwin Gentz
Try to lower the priority of your _collapsedtextHeightConstraint
to 999. That way the system supplied UIView-Encapsulated-Layout-Height
constraint always takes precedence.
尝试将您的优先级降低_collapsedtextHeightConstraint
到 999。这样系统提供的UIView-Encapsulated-Layout-Height
约束总是优先。
It is based on what you return in -tableView:heightForRowAtIndexPath:
. Make sure to return the right value and your own constraint and the generated one should be the same. The lower priority for your own constraint is only needed temporarily to prevent conflicts while collapse/expand animations are in flight.
它基于您返回的内容 -tableView:heightForRowAtIndexPath:
。确保返回正确的值,并且您自己的约束和生成的约束应该相同。您自己的约束的较低优先级仅用于在折叠/展开动画进行时临时防止冲突。
回答by Golden Thumb
I have a similar scenario: a table view with one row cell, in which there are a few lines of UILabel objects. I'm using iOS 8 and autolayout.
我有一个类似的场景:一个带有一行单元格的表格视图,其中有几行 UILabel 对象。我正在使用 iOS 8 和自动布局。
When I rotated I got the wrong system calculated row height (43.5 is much less than the actual height). It looks like:
当我旋转时,我得到了错误的系统计算行高(43.5 远小于实际高度)。看起来像:
"<NSLayoutConstraint:0x7bc2b2c0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7bc37f30(43.5)]>"
It's not just a warning. The layout of my table view cell is terrible - all text overlapped on one text line.
这不仅仅是一个警告。我的表格视图单元格的布局很糟糕 - 所有文本都重叠在一个文本行上。
It surprises me that the following line "fixes" my problem magically(autolayout complains nothing and I get what I expect on screen):
令我惊讶的是,以下行神奇地“修复”了我的问题(自动布局没有任何抱怨,我在屏幕上得到了我所期望的):
myTableView.estimatedRowHeight = 2.0; // any number but 2.0 is the smallest one that works
with or without this line:
有或没有这条线:
myTableView.rowHeight = UITableViewAutomaticDimension; // by itself this line only doesn't help fix my specific problem
回答by Jeff Bowen
I was able to get the warning to go away by specifying a priorityon one of the values in the constraint the warning messages says it had to break (below "Will attempt to recover by breaking constraint"
). It appears that as long as I set the priority to something greater than 49
, the warning goes away.
通过在警告消息说它必须中断的约束中的一个值上指定优先级,我能够使警告消失(如下"Will attempt to recover by breaking constraint"
)。似乎只要我将优先级设置为大于49
,警告就会消失。
For me this meant changing my constraint the warning said it attempted to break:
对我来说,这意味着改变我的约束,警告说它试图打破:
@"V:|[contentLabel]-[quoteeLabel]|"
@"V:|[contentLabel]-[quoteeLabel]|"
to:
到:
@"V:|-0@500-[contentLabel]-[quoteeLabel]|"
@"V:|-0@500-[contentLabel]-[quoteeLabel]|"
In fact, I can add a priority to any of the elements of that constraint and it will work. It doesn't seem to matter which one. My cells end up the proper height and the warning is not displayed. Roger, for your example, try adding @500
right after the 388
height value constraint (e.g. 388@500
).
事实上,我可以为该约束的任何元素添加优先级,它会起作用。哪一个似乎并不重要。我的单元格最终达到了正确的高度,并且不显示警告。罗杰,例如,尝试@500
在388
高度值约束(例如388@500
)之后添加。
I'm not entirely sure why this works but I've done a little investigating. In the NSLayoutPriority enum, it appears that the NSLayoutPriorityFittingSizeCompression
priority level is 50
. The documentation for that priority level says:
我不完全确定为什么会这样,但我做了一些调查。在NSLayoutPriority 枚举中,NSLayoutPriorityFittingSizeCompression
优先级似乎是50
. 该优先级的文档说:
When you send a fittingSize message to a view, the smallest size that is large enough for the view's contents is computed. This is the priority level with which the view wants to be as small as possible in that computation. It's quite low. It is generally not appropriate to make a constraint at exactly this priority. You want to be higher or lower.
当您向视图发送 fitSize 消息时,将计算视图内容足够大的最小尺寸。这是视图希望在该计算中尽可能小的优先级。这是相当低的。在这个优先级上进行约束通常是不合适的。你想要更高或更低。
The documentationfor the referenced fittingSize
message reads:
引用消息的文档fittingSize
如下:
The minimum size of the view that satisfies the constraints it holds. (read-only)
AppKit sets this property to the best size available for the view, considering all of the constraints it and its subviews hold and satisfying a preference to make the view as small as possible. The size values in this property are never negative.
满足其拥有的约束的视图的最小尺寸。(只读)
AppKit 将此属性设置为视图可用的最佳大小,考虑到它及其子视图持有的所有约束并满足使视图尽可能小的偏好。此属性中的大小值从不为负。
I haven't dug beyond that but it does seem to make sense that this has something to do with where the problem lies.
我还没有深入挖掘,但这似乎与问题所在有关。
回答by Clifton Labrum
I was able to resolve this error by removing a spurious cell.layoutIfNeeded()
that I had in my tableView
's cellForRowAt
method.
我能够通过删除cell.layoutIfNeeded()
我tableView
的cellForRowAt
方法中的一个虚假来解决这个错误。
回答by UMAD
99.9% of the time, while using custom cells or headers, all conflicts of UITableViews
occur when the table loads of the first time. Once loaded you will usually not see the conflict again.
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:
发生这种情况是因为大多数开发人员通常使用某种固定高度或锚点约束来布局单元格/标题中的元素。发生冲突是因为当第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
])
回答by Austin
Instead of informing the table view to update its constraints, try reloading the cell:
不要通知表视图更新其约束,而是尝试重新加载单元格:
[tableView beginUpdates];
[_briefCell collapse:!_showFullBriefText];
[tableView reloadRowsAtIndexPaths:@[[tableView indexPathForCell:_briefCell]] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
UIView-Encapsulated-Layout-Height
is probably the height the table view calculated for the cell during the initial load, based on the cell's constraints at that time.
UIView-Encapsulated-Layout-Height
可能是表格视图在初始加载期间为单元格计算的高度,基于当时单元格的约束。
回答by Cullen SUN
Another possibility:
另一种可能:
If you using auto layout to calculate the cell height (contentView's height, most of the time as below), and if you have uitableview separator, you need to add the separator height, in order to return for the cell height. Once you get the correct height, you won't have that autolayout warning.
如果您使用自动布局计算单元格高度(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
}
回答by Phu Nguyen
回答by Che
I had this error when using UITableViewAutomaticDimension and changing a height constraint on a view inside the cell.
使用 UITableViewAutomaticDimension 并更改单元格内视图的高度约束时出现此错误。
I finally figured out that it was due to the constraint constant value not being rounded up to the nearest integer.
我终于发现这是由于约束常量值没有被四舍五入到最接近的整数。
let neededHeight = width / ratio // This is a CGFloat like 133.2353
constraintPictureHeight.constant = neededHeight // Causes constraint error
constraintPictureHeight.constant = ceil(neededHeight) // All good!
回答by Alcides Eduardo Zelaya
After spending some hours scratching my head with this bug I finally found a solution that worked for me. my main problem was that I had multiple nibs registered for different cell types but one cell type specifically was allowed to have different sizes(not all instances of that cell are going to be the same size). so the issue arose when the tableview was trying to dequeue a cell of that type and it happened to have a different height. I solved it by setting
在花了几个小时为这个错误挠头后,我终于找到了一个对我有用的解决方案。我的主要问题是我为不同的单元格类型注册了多个笔尖,但特别允许一种单元格类型具有不同的大小(并非该单元格的所有实例都将具有相同的大小)。因此,当 tableview 试图使该类型的单元格出列并且它碰巧具有不同的高度时,问题就出现了。我通过设置解决了
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
whenever the cell had its data to calculate its size. I figure it can be in
每当单元格有数据来计算其大小时。我想它可以在
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
something like
就像是
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
Hope this helps!
希望这可以帮助!