UITableViewCell四舍五入错误与NSAutoresizingMaskLayoutConstraint,但大小正确设置在故事板和heightForRowAtIndexPath:

我想使用AutoLayout在我的表格视图单元格中configuration子视图,并在理想的情况下,希望表视图单元格,以尽可能高,以包含所有的子视图。 然而,这看起来不可能,因为单元格的高度是在单元格被实际创build之前确定的。

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

现在,我的表格视图单元格看起来像这样(从故事板的截图):

表视图单元格与自动布局。两个无标签的约束条件都是10

有两个没有显示大小的约束,它们的大小都是10(button顶部容器视图以及滑块和标签中间的距离)。

从上到下发生以下距离:

  • 10(距离)
  • 50(button高度)
  • 20(距离)
  • 20(标签高度)
  • 10(距离)
  • 30(滑块的高度)
  • 20(距离)

导致总高度为160。

这正是我在这个单元的检查员所设定的:

表格视图单元格的检查员显示表格视图单元格的高度为160

但是从第一个屏幕截图中可以看到,Interface builder抱怨约束是冲突的(这就是为什么它们显示为红色)。 如果我把高度设置为161,那么IB是满意的,但这是错误的。

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

 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中的一个显示错误,但现在看起来似乎是在创造一个错误的约束。 它创build了160.5(或159.5)而不是我指定的160的约束。 这是为什么? 我能做些什么呢?

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

更新: 159.5不只是因为我刚才注意到的故事板设置,这是故事板设置和tableView:heightForRowAtIndexPath:的返回值的奇怪组合。 以下是根据故事板高度(sb)设置和tableView:heightForRowAtIndexPath:方法(方法)的返回值生成的autoresizingmasklayoutconstraint的高度的一些示例。 在所有情况下,子视图的约束应该导致160的高度,并且不会改变。

  1. 160(sb)&160(方法):159.5(约束)
  2. 161(sb)&160(方法):159.5(约束)
  3. 160(sb)&161(方法):160.5(约束)
  4. 162(sb)&161(方法):162(约束)
  5. 161(sb)&162(方法):161(约束)
  6. 162(sb)&162(方法):162(约束)

所以我想,对于(6)他们都同意,我只是把标签的高度设为22,所以根据子视图的总高度也是162。 结果:

6A。 162(sb)&162(方法),162(子视图总高度):161.5(约束)

什么?!

任何想法发生了什么?

更新2我提供了一个在Github上重现问题的示例项目。

SeparatorcontentView的高度相混淆,或者应该禁用它(如果需要,则replace为自定义Separator ),以使contentView高度与cell高度匹配,或者考虑到contentView高度可以将约束更改为更灵活不匹配cell的高度。 做这两个会更好。

现在你已经把这个例子上传到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; } 

如果我没有弄错,那就是你以后的事情,也就是让约束本身决定细胞的高度。