具有自动布局的自定义 UITableViewCell 会导致警告

Posted

技术标签:

【中文标题】具有自动布局的自定义 UITableViewCell 会导致警告【英文标题】:Custom UITableViewCell with autolayout cause a warning 【发布时间】:2014-12-14 18:43:50 【问题描述】:

对于我的项目,我需要显示一个包含大量信息的医生列表,为此我以编程方式创建了一个自定义单元格。以下是我的单元格视图的结构:

Cell.contentView
  | --> UIView
    | --> UILabel (Title)
    | --> UILabel (Subtitle)
    | --> UIView (a simple separator, with a 1px height constraint)
    | --> UILabel (Address, multilines)

这是我真正拥有的简化结构,但足以带来警告。

这是警告:

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:0x14f9a790 V:|-(11)-[UILabel:0x16058ea0'DR.NAME']   (Names: '|':DoctorHealthInformationView:0x16058f70 )>",
    "<NSLayoutConstraint:0x14f86300 V:[UILabel:0x16058ea0'DR.NAME']-(1.5)-[UILabel:0x160670e0'Chirurgien Dentiste']>",
    "<NSLayoutConstraint:0x14f86390 V:[UILabel:0x160670e0'Specialty']-(9)-[UIView:0x14e0fde0]>",
    "<NSLayoutConstraint:0x14f9ab20 V:[UIView:0x14e0fde0]-(8)-[KDCellLabel:0x14f90d10'Address\naddres...']>",
    "<NSLayoutConstraint:0x14f9ab50 KDCellLabel:0x14f90d10'Address\naddres...'.bottom == DoctorHealthInformationView:0x16058f70.bottom - 10>",
    "<NSLayoutConstraint:0x14f97a80 V:|-(0)-[DoctorHealthInformationView:0x16058f70]   (Names: '|':CustomDoctorCell:0x1605a890'OnlineCustomDoctorCell' )>",
    "<NSLayoutConstraint:0x14f88840 V:[DoctorHealthInformationView:0x16058f70]-(0)-[UIView:0x14f930d0]>",
    "<NSLayoutConstraint:0x14f889b0 V:[UIView:0x14f930d0(1)]>",
    "<NSLayoutConstraint:0x14f9ae10 UIView:0x14f9d330.bottom == CustomDoctorCell:0x1605a890'OnlineCustomDoctorCell'.bottom>",
    "<NSLayoutConstraint:0x14f9b120 V:[UIView:0x14f9d330(4)]>",
    "<NSLayoutConstraint:0x14f9af40 V:[UIView:0x14f930d0]-(0)-[UIView:0x14f9d330]>",
    "<NSLayoutConstraint:0x14f93020 'UIView-Encapsulated-Layout-Height' V:[CustomDoctorCell:0x1605a890'OnlineCustomDoctorCell'(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x14f86390 V:[UILabel:0x160670e0'Specialty']-(9)-[UIView:0x14e0fde0]>

我的限制:

我唯一的高度限制是在我的分隔视图上,标签被固定在所有侧面的超级视图上,以允许我的单元格的高度通过自动布局计算。如果我删除分隔视图并将地址标签的顶部直接固定到字幕标签的底部,警告就会消失。如果我在一个标签上添加高度限制,警告就会回来。

一些经典但可能很有趣的方法:

获取指定行的高度:

表视图控制器:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    Doctor *doctor = (Doctor *)[_doctorsToShow objectAtIndex:indexPath.row];
    static CustomDoctorCell *sizingCellClassic = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        sizingCellClassic = [[CustomDoctorCell alloc] initWithStyle:UITableViewCellStyleDefault
                                                    reuseIdentifier:classicDoctorCellIdentifier
                                                          forDoctor:doctor
                                                      showSpecialty:YES
                                               withAppointmentStyle:YES];
    );

    [sizingCellClassic updateContentForDoctor:doctor];
    return [CustomDoctorCell getCellHeightForCell:sizingCellClassic];

CustomDoctorCell:

+ (float) getCellHeightForCell:(CustomDoctorCell *)doctorCell

    [doctorCell setNeedsLayout];
    [doctorCell layoutIfNeeded];

    CGSize size = [doctorCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    return size.height;

我不明白我做错了什么,以及我必须做些什么来删除这个警告,我尝试下载this example form raywenderlich.com 并简单地在标签上添加高度限制,我有同样的警告。

还有一点,我必须完全兼容ios 7,所以我没有使用sdk 8引入的新功能。

【问题讨论】:

【参考方案1】:

我在故事板中使用原型单元时遇到了类似的情况; contentView 的 UIView-Encapsulated-Layout-Height 搞砸了一切。我的解决方案是做两件事:

首先,我将一个垂直约束的优先级设置为 999。

其次,我为 IB 中的 Table View Cell 设置“自定义”行高。

在我的情况下,它设置为 266,但我认为这并不重要,只要您选中了“自定义”复选框并且在行高输入中没有显示“默认”。

我最初担心较低优先级的垂直间隔约束意味着手动输入的自定义高度会优先,但事实并非如此。表格单元格遵守我给它的约束。

这似乎违反直觉,但我的预感是正在进行一些预计算,这会导致自定义高度和 contentView 内的垂直约束之间发生冲突,但在某个层点,可能在 layoutSubviews 中,约束优先并且该应用程序愉快地开展业务。因此,我认为该应用程序会查看所有内容,尝试打破约束以安抚 rowHeight 或estimatedRowHeight,然后返回并执行它最初应该做的事情。不过,这是一个完整的猜测。无论如何,它适用于我的情况。

您提到您的目标是 iOS7,所以我不确定它是否适合您,因为我只在 iOS8 中进行了测试,但我们的情况非常相似,值得一试。鉴于它是 iOS8,我正在使用新的功能。

    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.estimatedRowHeight = (UIApplication.sharedApplication().keyWindow?.bounds.height)! * (460.0/1334.0)

【讨论】:

在 iOS9 中将一个高度约束优先级设置为低于 1000 对我有用。我仍然不明白为什么,我检查了很多次自动布局约束,它们应该没有问题。 UITableViewCell 的 Auto Layout 让我头疼了很多次...【参考方案2】:

单元格的初始高度可能小于垂直约束。这会产生初始高度冲突,直到 contentView 的框架发生变化。

您可以使用以下方法之一解决此问题:

增加故事板中单元格的高度以适应内容。

将单元格的 contentView 的边界更改为更大的尺寸:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

您将在this auto layout question 的答案中找到更多详细信息。

【讨论】:

以上是关于具有自动布局的自定义 UITableViewCell 会导致警告的主要内容,如果未能解决你的问题,请参考以下文章

如何使自动布局与 XIB 中的自定义 UIView 一起使用?

UIImageView 在具有不同高度的自定义 UITableViewCell 内自动调整大小

如何在 iOS 6 中使用具有多个子视图的现有自定义视图自动布局

方向更改时的自定义 TableViewCell 自动布局问题

UIView 无法在具有自动布局的 UIScrollView 中正确居中

具有自动布局的 UITableView 中的动态列