UITableViewCell 中的 NSLayoutConstraint 中断

Posted

技术标签:

【中文标题】UITableViewCell 中的 NSLayoutConstraint 中断【英文标题】:NSLayoutConstraint break within UITableViewCell 【发布时间】:2014-10-27 14:01:20 【问题描述】:

当使用自动布局约束以编程方式将viewController.view 添加到表格视图单元格时,它有时布局不正确。知道单元格具有固定高度 (50) 并且子视图包含一个 UIButton 和一个 UITableView 在开始时不包含单元格,直到用户执行某些操作。 以下是将子视图添加到单元格的代码:

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

    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    //Get sub item objects
    BookItem * newItem = self.subItems[indexPath.row];
    NSString * newItemKey = [NSString stringWithFormat:@"%i", newItem.iD];
    NSString * currentCellItemKey = [NSString stringWithFormat:@"%i", cell.tag];
    BookTreeItemViewController_iPad * bookTreeItemVC = self.subItemVCs[currentCellItemKey];
    if (!bookTreeItemVC)
    
        bookTreeItemVC = [self.storyboard instantiateViewControllerWithIdentifier:@"BookTreeItemViewController_iPad"];
        //Clear cell
        for (UIView * subView in cell.contentView.subviews)
            [subView removeFromSuperview];
        //Add sub item view to cell
        [bookTreeItemVC.view setTranslatesAutoresizingMaskIntoConstraints:NO];
        [cell.contentView addSubview:bookTreeItemVC.view];
        [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[item]|" options:nil metrics:nil views:@@"item": bookTreeItemVC.view]];
        [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[item]|" options:nil metrics:nil views:@@"item": bookTreeItemVC.view]];
    
    bookTreeItemVC.bookItem = newItem;

    //Replace the old book tree item view controller with the new one
    [self.subItemVCs setValue:nil forKey:currentCellItemKey];
    cell.tag = newItem.iD;
    self.subItemVCs[newItemKey] = bookTreeItemVC;

    return cell;

这是限制警告:

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:0x7c091240 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7c0895d0(49.5)]>",
    "<NSLayoutConstraint:0x7a74f250 V:[UIButton:0x7a7482a0'Title']-(8)-[UITableView:0x7aad7a00]>",
    "<NSLayoutConstraint:0x7a74f2b0 V:[_UILayoutGuide:0x7a74ee70]-(0)-[UIButton:0x7a7482a0'Title']>",
    "<NSLayoutConstraint:0x7a74f310 V:[UITableView:0x7aad7a00]-(0)-[_UILayoutGuide:0x7a74ef60]>",
    "<_UILayoutSupportConstraint:0x7a739510 V:[_UILayoutGuide:0x7a74ee70(87)]>",
    "<_UILayoutSupportConstraint:0x7a74e2e0 V:|-(0)-[_UILayoutGuide:0x7a74ee70]   (Names: '|':UIView:0x7a74ee00 )>",
    "<_UILayoutSupportConstraint:0x7a747900 V:[_UILayoutGuide:0x7a74ef60(0)]>",
    "<_UILayoutSupportConstraint:0x7a748130 _UILayoutGuide:0x7a74ef60.bottom == UIView:0x7a74ee00.bottom>",
    "<NSLayoutConstraint:0x7a750c10 V:|-(0)-[UIView:0x7a74ee00]   (Names: '|':UITableViewCellContentView:0x7c0895d0 )>",
    "<NSLayoutConstraint:0x7a748270 V:[UIView:0x7a74ee00]-(0)-|   (Names: '|':UITableViewCellContentView:0x7c0895d0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7a74f250 V:[UIButton:0x7a7482a0'Title']-(8)-[UITableView:0x7aad7a00]>

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

顺便说一句,我从警告中注意到顶部布局指南的高度为 (87),应该是 (0)

【问题讨论】:

你能发布你的代码吗?以便于识别 我更新了帖子并添加了添加子视图及其约束的代码。 【参考方案1】:

是的,你是对的。

"<_UILayoutSupportConstraint:0x7a739510 V:[_UILayoutGuide:0x7a74ee70(87)]>",

不知何故,您的视图控制器具有最高支持值为 87 的布局指南。此崩溃与您的固定单元格高度有关,因此它消除了按钮和 tableview 之间距离的约束。

也许您可以发布 BookTreeItemViewController_iPad 的布局代码或

尝试从新的 xcode 进行 3D 调试以找出 87 像素是什么? 将您的 TableView.rowHeight 设置为 UITableViewAutomaticDimension,以便您的单元格高度是动态的。然后,您可以再次看到 87 像素是多少。

【讨论】:

从3D视图调试来看,自定义视图的子视图放在容器视图的外面和上面。 这是正确的,因为它是子视图。但是自定义视图高度是显示额外的 87 像素,还是只显示 UIButton 和 UITableView?那么按钮和表格视图的组合高度如何?是否低于 50 像素(您的单元格高度)? 在使单元格高度动态化(我不想要)后,此警告出现“仅警告一次:检测到约束模糊地建议 tableview 单元格的内容视图高度为零的情况。我们”重新考虑意外折叠并改用标准高度。“ 我的意思是子视图不仅在它的前面,而且在容器视图边界之外。 嗯.. 以前从未见过该警告。但这是否意味着您的单元格以某种方式以高度 0 结束? ViewController(用于单元格)是否已初始化?你能看到单元格上的按钮吗?我能想到的只是您要添加到单元格的 ViewController 不知何故尚未初始化,或者按钮的高度为 0,因为没有为按钮高度约束指定最小高度。【参考方案2】:

当您删除视图时,问题看起来像,您的约束没有被删除。所以只需替换以下代码:-

替换:-

for (UIView * subView in cell.contentView.subviews)
 [subView removeFromSuperview];

到:-

[cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];     

并且还以更有效的方式修改了以下内容:-

NSView *views=bookTreeItemVC.view;
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[item]|" options:0l metrics:nil views:NSDictionaryOfVariableBindings(views)]];
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[item]|" options:0l metrics:nil views:NSDictionaryOfVariableBindings(views)]];

【讨论】:

不,删除视图会从其超级视图中删除其约束。我测试过了。【参考方案3】:

经过两天的研究,我不得不从 IB(故事板)中删除子视图(放入单元格中的视图)的表视图,并以编程方式添加它及其约束。所以,现在一切正常。

【讨论】:

以上是关于UITableViewCell 中的 NSLayoutConstraint 中断的主要内容,如果未能解决你的问题,请参考以下文章

更改 UITableViewCell 中的对象也更改了重用 UITableViewCell 的对象

确定 UITableViewCell 中的 UIButton

UITableViewCell 事件中的 UIButton 不起作用

UITableViewCell 中的 UICollectionView

UITableVIewCell 中的 UIScrollView 不会滚动

UITableViewCell 中的 UITextField - UIButton