什么是NSLayoutConstraint“UIView-Encapsulated-Layout-Height”,我该如何强迫它重新计算干净
我有一个UITableView
在iOS 8下运行,我使用故事板中约束的自动单元格高度。
我的一个单元格包含单个UITextView
,我需要它根据用户input进行收缩和展开 – 点击缩小/展开文本。
我这样做是通过向文本视图添加一个运行时约束,并在约束条件中改变常量来响应用户事件:
-(void)collapse:(BOOL)collapse; { _collapsed = collapse; if(collapse) [_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0 else [_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]]; [self setNeedsUpdateConstraints]; }
当我这样做,我把它包装在tableView
更新,并设置tableView
的需要updateConstraint:
[tableView beginUpdates]; [_briefCell collapse:!_showFullBriefText]; [tableView setNeedsUpdateConstraints]; // I have also tried // [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop]; // with exactly the same results. [tableView endUpdates];
当我这样做的时候,我的细胞确实膨胀了(并且在做animation时),但是我得到了一个约束警告:
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
(我猜这是自动单元格大小的计算高度),我应该如何强迫它重新计算干净?
尝试降低_collapsedtextHeightConstraint
的优先级为999.这样,系统提供的UIView-Encapsulated-Layout-Height
约束总是优先的。
它基于你在-tableView:heightForRowAtIndexPath:
返回的-tableView:heightForRowAtIndexPath:
。 确保返回正确的值和你自己的约束,生成的应该是相同的。 您自己的约束的较低优先级只是临时需要,以防止崩溃/展开animation在飞行中的冲突。
我有一个类似的情况:一个单行单元格,其中有几行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
我可以通过指定约束条件中的某个值的优先级来使警告消失,警告消息指出它必须中断(在"Will attempt to recover by breaking constraint"
)。 看来只要我把重点放在大于49
东西上,警告就会消失。
对我来说,这意味着改变我的约束,警告说它试图破坏:
@"V:|[contentLabel]-[quoteeLabel]|"
至:
@"V:|-0@500-[contentLabel]-[quoteeLabel]|"
实际上,我可以为该约束的任何元素添加一个优先级,它将起作用。 这似乎并不重要。 我的单元格结束了适当的高度,警告不显示。 罗杰,例如,你可以尝试在388
高度值约束(例如388@500
)之后加上@500
。
我不完全确定这是为什么,但我做了一些调查。 在NSLayoutPriority枚举中 ,看起来NSLayoutPriorityFittingSizeCompression
优先级是50
。 该优先级文件说:
在向视图发送fittingSize消息时,计算视图内容足够大的最小尺寸。 这是视图希望在该计算中尽可能小的优先级。 这是相当低的。 确切地说,在这个优先权上制约是不合适的。 你想要更高或更低。
引用的fittingSize
消息的文档如下所示:
满足其约束条件的视图的最小尺寸。 (只读)
AppKit将这个属性设置为可用于视图的最佳大小,考虑到它及其子视图的所有约束,并满足使视图尽可能小的优先select。 此属性中的大小值永远不会为负数。
我还没有超出这个范围,但是这似乎有道理,这与问题出在哪里有关。
而不是通知表视图更新其约束,请尝试重新加载单元格:
[tableView beginUpdates]; [_briefCell collapse:!_showFullBriefText]; [tableView reloadRowsAtIndexPaths:@[[tableView indexPathForCell:_briefCell]] withRowAnimation:UITableViewRowAnimationNone]; [tableView endUpdates];
UIView-Encapsulated-Layout-Height
可能是表视图在初始加载期间根据单元格的约束计算的表视图的高度。
另一种可能性
如果使用自动布局来计算单元格高度(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 }
调整文本视图以适应其内容,并更新高度约束常量到最终的高度,修复了UIView-Encapsulated-Layout-Height
约束冲突,例如:
[self.textView sizeToFit]; self.textViewHeightConstraint.constant = self.textView.frame.size.height;
花了几个小时用这个bug搔了我脑袋,我终于find了一个解决scheme,为我工作。 我的主要问题是,我有不同的细胞types注册多个笔尖,但一个细胞types被允许具有不同的大小(并不是该细胞的所有实例将是相同的大小)。 所以这个问题出现时,tableview试图出列这种types的单元格,它碰巧有不同的高度。 我通过设置解决了它
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});
希望这可以帮助!
TableView从委托获取indexPath处单元格的高度。 然后从cellForRowAtIndexPath
获取单元格:
top (10@1000) cell bottom (0@1000)
如果与UIView-Encapsulated-Layout-Height:0 @ 1000冲突的cell.contentView.height:0 // < – >(UIView-Encapsulated-Layout-Height:0 @ 1000)top(10 @ 1000)
因为它们的优先级是等于1000.在UIView-Encapsulated-Layout-Height
的优先级下我们需要优先级。
我收到这样的消息:
无法同时满足约束…
…
…
…
NSLayoutConstraint:0x7fe74bdf7e50'UIView-Encapsulated-Layout-Height'V:[UITableViewCellContentView:0x7fe75330c5c0(21.5)]
…
…
将尝试通过中断约束来恢复NSLayoutConstraint:0x7fe0f9b200c0 UITableViewCellContentView:0x7fe0f9b1e090.bottomMargin == UILabel:0x7fe0f9b1e970.bottom
我用UITableViewAutomaticDimension
自定义UITableViewCell
的高度。 我也实现了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-|
。 但是指定大小对于我来说并不是问题,它可以摆脱日志,而且我也不需要降低所需约束的优先级。
正如Jesse在提问中所提到的,这对我来说是有效的:
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
仅供参考,这个问题在iOS 10中不会发生。