【问题标题】:Trouble with AutoLayout on UITableViewCellUITableViewCell 上的自动布局问题
【发布时间】:2013-10-01 15:40:04
【问题描述】:

我在 xcode 5 项目上遇到自动布局问题。我在内部使用带有导航控制器的普通视图控制器。我在上半部分有一个MKMapView,在下半部分有一个UITableView。我正在使用storyboards,并且已经配置了原型UITableViewCell,但是我正在通过代码添加约束。我已经仔细检查了原型中的每个控件,并没有看到那里配置了任何约束。当我为UITableViewCell 添加约束时,我的问题就出现了。我在单元格中有以下代码:

-(void)updateConstraints {
    [super updateConstraints];
    //first remove old constraints
    [self removeConstraints:self.constraints];
    [self.nameLabel removeConstraints:self.nameLabel.constraints];
    [self.addressLabel removeConstraints:self.nameLabel.constraints];
    [self.rentableSquareFeetLabel removeConstraints:self.rentableSquareFeetLabel.constraints];
    [self.lastSaleAmountLabel removeConstraints:self.lastSaleAmountLabel.constraints];
    [self.lastSaleDateLabel removeConstraints:self.lastSaleAmountLabel.constraints];
    [self.thumbnailImageView removeConstraints:self.thumbnailImageView.constraints];

    //then set up constraints
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_thumbnailImageView, _nameLabel, _rentableSquareFeetLabel, _lastSaleAmountLabel, _addressLabel, _lastSaleDateLabel);
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_thumbnailImageView(60)]-[_nameLabel(<=200)]-(>=8)-[_rentableSquareFeetLabel]-(>=8)-[_lastSaleAmountLabel]|" options:0 metrics:nil views:viewsDictionary]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_nameLabel]-(-4)-[_addressLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_lastSaleAmountLabel]-(-4)-[_lastSaleDateLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]];
}

我在调试控制台中得到以下信息。异常由第一行 addConstraints 触发。如果我只是继续这些,那么最终一切都会按原样显示,因为看起来 xcode 正在选择打破正确的约束:

2013-09-25 15:07:14.169 PECProperties[32381:a0b] 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)  (
    "<NSIBPrototypingLayoutConstraint:0x9d56c70 'IB auto generated at build time for view with fixed frame' H:|-(0)-[UIImageView:0x9d558f0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>",
    "<NSIBPrototypingLayoutConstraint:0x9d56d20 'IB auto generated at build time for view with fixed frame' H:[UIImageView:0x9d558f0(60)]>",
    "<NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>",
    "<NSLayoutConstraint:0x9d53830 H:[UIImageView:0x9d558f0]-(NSSpace(8))-[UILabel:0x9d559e0]>" )

Will attempt to recover by breaking constraint  <NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>

Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

第三个 NSIBPrototypingLayoutConstraint 显示视图边缘和标签之间的 78 个点。那是原型大致定位的位置(如果我在原型中移动它,我会在调试控制台中看到约束的变化),但这与我自己的图像视图和标签之间的“标准”距离约束相冲突.

我尝试在视图控制器的cellForRowAtIndexPath 中设置translatesAutoresizingMaskIntoConstraints=NO,但这似乎也无济于事。如何修复布局?

【问题讨论】:

  • 我注意到 iOS7 中的一个单独的错误导致了类似的问题。我在 IB 中指定了所有约束,XCode 很高兴。但是异常中所有垂直尺寸的总和

标签: ios objective-c uitableview autolayout


【解决方案1】:

这里有几件事要介绍:

  1. 您遇到的NSIBPrototypingLayoutConstraint 约束(并且会导致异常)由 Interface Builder 自动生成,以使您的 Storyboard 或 XIB 视图布局明确。这样做非常偷偷摸摸,但它会自动添加所需的最小约束,以便完全指定每个模棱两可的视图的位置和大小。这是对 Xcode 4 的更改,因为在 Xcode 4 中,您不能在 Interface Builder 中使用模棱两可的布局。使用 Xcode 5 及更高版本您可以,但是如果您的布局在编译时不明确,IB 会为您自动生成这些约束。

    解决此问题的方法是在 Interface Builder 中添加所需的最小约束,以便完全指定每个视图的位置和大小,然后选择每个不需要的约束,转到右侧边栏的属性检查器,然后选中该框占位符 - 构建时移除旁边。

    此复选框不仅会删除您添加的约束,而且最重要的是它会阻止自动生成的 IB 约束取而代之! (正如您可以想象的那样,当您在 IB 中有多个视图并希望在代码中管理所有约束时,这是非常乏味的。因此,您可能希望避免将 IB 完全用于您打算在其中实现 Auto 的视图层次结构以编程方式布局。)

    Placeholder 约束和 Uninstalled 约束有什么区别?这是我的Adaptive Auto Layout talk (video) (PDF slides) 比较两者的幻灯片:

  2. updateConstraints 中,您不想删除约束并重新添加它们,就像您在那里一样。为什么不?从本质上讲,这对性能来说很糟糕,我已经与 Apple 工程师确认这不是一个好主意。有关更多详细信息,请参阅question/answer I have posted here,以及此answer。为了防止多次添加约束,请使用布尔标志(例如hasSetupConstraints),一旦您第一次设置约束,您就设置为YES,如果再次调用updateConstraints,您可以立即返回如果您没有要添加的新约束。更多讨论请见this question

  3. 您用来移除约束的代码可能无法完全运行。这是因为[view removeConstraints:view.constraints] 只会删除已添加到view 的约束——请记住,可以将约束添加到它们约束的视图的任何公共父视图中——并且添加到view 的约束可能不是唯一的影响view布局的!如果你需要删除一些约束,你应该在一个属性中存储对每个约束的引用(例如,一个包含 NSLayoutConstraint 实例的 NSArray 属性),然后使用 NSLayoutConstraint 或 the PureLayout open-source library 上的 API 停用/删除这些约束。您应该只停用/删除尽可能少的约束,因为这样做的计算成本很高。另一方面,更改任何约束的constant 非常有效且值得鼓励,您无需删除或重新添加约束即可。

【讨论】:

  • 非常感谢您的帮助。我在 IB 中添加了约束,将它们标记为占位符,并避免了异常。在考虑您的其余建议时,我认为没有太多理由不能在 IB 中指定所有这些约束并完全删除代码。这是我的第一个带有自动布局的项目,在视图控制器上我需要在旋转时添加/删除约束,所以我基本上试图在表格视图单元格上采用相同的方法。但正如你所指出的,我不需要。再次感谢!
  • 没问题。如果您可以从 IB 获得良好的约束,那就去做吧。但就我个人而言,我基本上已经完全停止使用 IB,尤其是在自动布局方面。 IB 看起来很简单,但除了最简单的视图设置(通常,你看到的不是你得到的!)之外,它会给任何东西带来很大的痛苦。无论如何...随时询问您是否遇到任何其他绊脚石。
  • 我不明白您所说的“这个复选框不仅会删除您添加的约束”是什么意思,为什么要删除您刚刚添加的约束?
  • @drc 如果您阅读原始问题,Stephen 将在代码中添加他所有的自动布局约束,而不是从 IB 中添加(这是完全有效的)。为了从 xib/storyboard 加载视图并在代码中执行所有约束,您不需要任何 IB 约束(导致冲突)。而且由于 Xcode 会为不明确的布局自动生成 IB 约束,因此您必须首先添加足够的约束以完全指定所有视图,然后您可以单击每个约束上的上述复选框。不幸的是,没有其他方法可以防止添加自动生成的约束。
  • @fatuhoku 使用最新的 Xcode 6 beta 5,在 IB 中编辑 .xib 文件时,单击约束和属性检查器后,我仍然看到“占位符 - 构建时删除”复选框在 Xcode 5 中显示的同一位置。
猜你喜欢
  • 2017-02-13
  • 1970-01-01
  • 1970-01-01
  • 2013-10-08
  • 2018-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多