使用NSAutoresizingMaskLayoutConstraint进行UITableViewCell舍入错误,但在Storyboard和heightForRowAtIndexPath中正确设置了大小:

时间:2014-03-20 16:56:15

标签: ios objective-c uitableview autolayout

我正在尝试使用AutoLayout在我的表格视图单元格中配置子视图,并且在理想情况下,希望表格视图单元格与包含所有子视图所需的一样高。但是,这似乎不可能,因为在实际创建单元格之前确定单元格的高度。

所以,现在,我只是查看了我设置的约束并计算了包含所有内容所需的总高度,并在故事板中将其设置为此特定TableViewCell原型单元格的行高度,并且我还在此处返回此高度tableView:heightForRowAtIndexPath:方法。

现在,我的表格视图单元格如下(故事板的截图):

table view cell with auto layout. The two unlabeled constraints have both the size 10

有两个限制没有显示尺寸,它们都有10的大小(按钮顶部容器视图和滑块与中间标签之间的距离)。

从上到下出现以下距离:

  • 10(距离)
  • 50(按钮高度)
  • 20(距离)
  • 20(标签高度)
  • 10(距离)
  • 30(滑块高度)
  • 20(距离)

导致总高度为160。

这正是我在这个单元格的检查器中设置的内容:

inspector of table view cell showing height of the table view cell as 160

但是从第一个屏幕截图中可以看出,“界面”构建器会抱怨约束是冲突的(这就是为什么它们以红色显示)。如果我将高度设置为161,则IB感到满意,但这是错误的。

另外,如果我这样做,由于约束冲突,我在运行时会遇到异常:

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:0x8d80240 V:[UISlider:0x8d81190(30)]>",
"<NSLayoutConstraint:0x8d833e0 V:[UILabel:0x8d83300(20)]>",
"<NSLayoutConstraint:0x8d83750 V:[UIButton:0x8d83600(50)]>",
"<NSLayoutConstraint:0x8d85050 V:|-(10)-[UIButton:0x8d83600]   (Names: '|':UITableViewCellContentView:0x8d80ef0 )>",
"<NSLayoutConstraint:0x8d851d0 V:[UILabel:0x8d83300]-(10)-[UISlider:0x8d81190]>",
"<NSLayoutConstraint:0x8d85200 V:[UISlider:0x8d81190]-(20)-|   (Names: '|':UITableViewCellContentView:0x8d80ef0 )>",
"<NSLayoutConstraint:0x8d85320 V:[UIButton:0x8d83600]-(20)-[UILabel:0x8d83300]>",
"<NSAutoresizingMaskLayoutConstraint:0x8d8b7a0 h=--& v=--& V:[UITableViewCellContentView:0x8d80ef0(161)]>"

最后一个是我没有明确设置的唯一一个,但它似乎是从故事板中的行高设置生成的,因为我的tableView:heightForRowAtIndexPath:方法返回160:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == self.fetchedItemSetsController.fetchedObjects.count - 1)
    {
        return 160;
    }
    return 44;
}

(目前我总是希望最后一个单元格是大而特殊的单元格)

所以,好吧,当我将行高设置为160时,IB抱怨,但当我将其设置为161时,运行时会抱怨。所以我尝试忽略IB并在故事板中将行高设置为160(如第二个屏幕截图所示)。在这种情况下,我收到相同的错误消息,但差别很小:

"<NSLayoutConstraint:0x17809ce80 V:[UISlider:0x125613660(30)]>",
"<NSLayoutConstraint:0x1782814f0 V:[UILabel:0x125615100(20)]>",
"<NSLayoutConstraint:0x178281a90 V:[UIButton:0x125615b50(50)]>",
"<NSLayoutConstraint:0x178281b80 V:|-(10)-[UIButton:0x125615240]   (Names: '|':UITableViewCellContentView:0x178161980 )>",
"<NSLayoutConstraint:0x178281c20 UIButton:0x1256157b0.height == UIButton:0x125615240.height>",
"<NSLayoutConstraint:0x178281d10 UIButton:0x1256157b0.height == UIButton:0x125615980.height>",
"<NSLayoutConstraint:0x178281e00 V:[UILabel:0x125615100]-(10)-[UISlider:0x125613660]>",
"<NSLayoutConstraint:0x178281e50 V:[UISlider:0x125613660]-(20)-|   (Names: '|':UITableViewCellContentView:0x178161980 )>",
"<NSLayoutConstraint:0x178281f40 UIButton:0x125615980.height == UIButton:0x125615b50.height>",
"<NSLayoutConstraint:0x178282030 V:[UIButton:0x125615240]-(20)-[UILabel:0x125615100]>",
"<NSAutoresizingMaskLayoutConstraint:0x178283340 h=--& v=--& V:[UITableViewCellContentView:0x178161980(159.5)]>"

表格视图单元格高度的约束现在是159.5而不是160.我之前也遇到过160.5,它具有相同的故事板设置,但我不确定它来自何处。

所以,首先我认为它只是IB中的显示错误,但现在它实际上似乎正在创建错误的约束。它创建一个约为160.5(或159.5)的约束,而不是指定的160 I. 为什么?我该怎么办?

顺便说一句:细胞似乎正确显示,但我再次怀疑我能看到0.5分的差异。主要是,我想摆脱异常,因为它们使调试更加困难,但我也想知道这里发生了什么。

更新 由于我刚刚注意到的故事板设置,159.5不是JUST,它是故事板设置和tableView:heightForRowAtIndexPath:的返回值的奇怪组合。 以下是生成的autoresizingmasklayoutconstraint高度的几个示例,具体取决于故事板高度(sb)设置和tableView:heightForRowAtIndexPath:方法(方法)的返回值。在所有情况下,子视图的约束应该导致高度为160并且不会更改。

  1. 160(sb)&amp; 160(方法):159.5(约束)
  2. 161(sb)&amp; 160(方法):159.5(约束)
  3. 160(sb)&amp; 161(方法):160.5(约束)
  4. 162(sb)&amp; 161(方法):162(约束)
  5. 161(sb)&amp; 162(方法):161(约束)
  6. 162(sb)&amp; 162(方法):162(约束)
  7. 所以我想,好吧,因为(6。)他们都同意,我只会将标签的高度设为22,所以根据子视图的总高度也是162。结果:

    6a上。 162(sb)&amp; 162(方法),162(子视图的总高度):161.5(约束)

    什么?!

    有什么想法在这里发生了什么?

    更新2 我提供了一个示例项目来重现问题on Github

2 个答案:

答案 0 :(得分:4)

现在您已将示例上传到github,我能够看到约束实际上是过度确定的。有太多“这等于那个”,尤其是在垂直间距/高度的区域。我简化了约束,并且能够将代码更改为:

-(CGFloat)tableView:(UITableView *)tableView 
    heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0)
    {
        return 44;
    } // else
    UITableViewCell* cell = 
        [tableView dequeueReusableCellWithIdentifier:@"LargeCell"];
    CGSize sz = 
        [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingExpandedSize];
    return sz.height;
}

如果我没有弄错的话,那就是你所追求的那种,即让约束本身决定细胞的高度。

答案 1 :(得分:4)

Separator正在弄乱contentView的高度,要么应该禁用它(如果需要,请替换为自定义的高度),以使contentView高度与cell高度相匹配考虑到contentView高度可能与cell的高度不匹配,{1}}或约束应更改为更灵活。做到这两点会更好。