【问题标题】:Auto layout constraints issue on iOS7 in UITableViewCellUITableViewCell中iOS7上的自动布局约束问题
【发布时间】:2013-10-08 14:23:59
【问题描述】:

我正在以编程方式使用自动布局约束来布局我的自定义 UITableView 单元格,并且我在 tableView:heightForRowAtIndexPath: 中正确定义了单元格大小

它在 iOS6 上运行良好,在 iOS7 上也看起来正常

但是当我在 iOS7 上运行应用程序时,我在控制台中看到的消息是这样的:

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.
2013-10-02 09:56:44.847 Vente-Exclusive[76306: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) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

而且确实在那个列表中有一个我不想要的约束:

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

我无法将contentViewtranslatesAutoresizingMaskIntoConstraints 属性设置为NO =>它会弄乱整个单元格。

44 是默认单元格高度,但我在表格视图委托中定义了我的自定义高度,那么为什么单元格 contentView 有这个约束?什么可能导致这种情况?

在 iOS6 中没有发生这种情况,在 iOS6 和 iOS7 上一切看起来都很好。

我的代码很大,所以我不会在此处发布,但如果您需要,请随时索取 pastebin。

在单元初始化时指定我的操作方式:

  • 我创建了所有标签、按钮等
  • 我将他们的 translatesAutoresizingMaskIntoConstraints 属性设置为 NO
  • 我将它们添加为单元格的contentView 的子视图
  • 我在contentView 上添加了约束

我也很想了解为什么这种情况只发生在 iOS7 上。

【问题讨论】:

  • 您的自定义单元格高度设置为多少?
  • 我的自定义单元格高度设置为 90
  • 一位同事昨天遇到了同样的问题,但默认的 width 为 320(对于 iPad 应用)。
  • 这里有一个示例项目演示了同样的问题:github.com/Alex311/TableCellWithAutoLayout 以下是我对它的一些观察:github.com/Alex311/TableCellWithAutoLayout/commit/…
  • 我遇到了同样的错误,但这是因为我从未初始化用于查找自定义单元格高度的额外原型单元格。

标签: ios ios7 uitableview autolayout nslayoutconstraint


【解决方案1】:

我也遇到了这个问题.. 似乎 contentView 的框架在调用 layoutSubviews 之前不会更新,但是单元格的框架会更早更新,此时 contentView 的框架设置为 {0, 0, 320, 44}对约束进行评估。

更详细地查看 contentView 后,似乎不再设置 autoresizingMasks。

在约束视图之前设置 autoresizingMask 可以解决此问题:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}

Swift5、ios14:

contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]

【讨论】:

  • 这很好,谢谢伙计。使用编辑样式时会发生什么?
  • @L14M333 请参阅我在此comment here 中发布的代码——基本上,您应该能够在添加约束之前设置self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);,这应该可以解决问题。
  • autoresizingMask 对我不起作用:初始约束已消失,但添加了 3 个新约束“<0x8b79740 h="-&-" v="-&-" uitableviewcellcontentview:0x8b44010.height="=" uitableviewcellscrollview:0x8b4a130.height><0x8b7b9f0 h="-&-" v="-&-" uitableviewcellscrollview:0x8b4a130.height="=" librarycell:0x8ac19d0.height><0x8b7c590 h="--&" v="--&" v:>
【解决方案2】:

显然使用 iOS 8 SDK 在 iOS 7 上的 UITableViewCell 和 UICollectionViewCell 有问题。

当单元格被重用时,您可以像这样更新单元格的 contentView:

对于静态 UITableViewController:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }

    //your code goes here

    return cell;
}

#endif
#endif

由于静态表视图控制器很脆弱,如果您实现一些数据源或删除门方法很容易被破坏 - 有一些检查将确保此代码只能在 iOS 7 上编译和运行

标准动态 UITableViewController 类似:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

对于这种情况,我们不需要编译额外检查,因为需要实现此方法。

这两种情况和 UICollectionViewCell 的想法是相同的,就像在此线程中评论的那样:Autoresizing issue of UICollectionViewCell contentView's frame in Storyboard prototype cell (Xcode 6, iOS 8 SDK) happens when running on iOS 7 only

【讨论】:

  • 这是最好的答案,或者至少对我来说是最好的解决方案。我的 Cell(自动布局规则)在带有 XCode6 的 iOS8 中运行良好,在带有 XCode 5 的 iOS7 和 6 中运行良好。我将 XCode 更新到 XCode6,但它不再在 iOS6 和 7 中运行。所以,谢谢!!!!
  • 这不再是 Xcode 6.1 的问题。另外,不要使用 NSFoundationVersionNumber,请参阅nshipster.com/swift-system-version-checking
  • @onmyway133:为什么这在 Xcode 6.1 中不再是问题了?即使我使用 Xcode 6.1 和 iOS 8.1 SDK,我仍然遇到问题。该问题仅发生在 iOS 7 上。更改边界或设置自动调整大小的蒙版可以解决问题。但是我使用了投票最多的答案或其中的 cmets 中所述的方法。
  • 是的,这是基于我 3 小时谷歌搜索的最佳答案。其他类似的“解决方案”不提供 cell.contentView.autoresizingMask 的完整列表。只有这个适用于我在 Xcode 6 中创建的 iPad 7.1 项目。
【解决方案3】:

也许设置视图的优先级大于750小于1000可以解决。

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",

【讨论】:

    【解决方案4】:

    如果在 iOS8 中运行良好,在 iOS7 中得到警告,您可以搜索故事板源代码,找到正确的 tableviewCell,然后在 tableviewCell 行后面附加 rect 属性。感谢kuchumovn

    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                    <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
    

    【讨论】:

      【解决方案5】:

      我最终没有在设计器中使用 UITableViewCell...我在那里创建自定义视图并以编程方式将其添加到单元格的内容视图中...对于一些帮助类别也没有代码样板...

      【讨论】:

        【解决方案6】:

        由于单元格被重复使用并且高度可以根据内容而改变,我认为一般来说最好将间距的优先级设置为小于要求的值。

        在您的情况下,UIImageView 与顶部的间距为 15,底部视图与底部的间距为 0。如果您将这些约束的优先级设置为 999(而不是 1000),则应用不会崩溃,因为这些约束不是必需的。

        一旦layoutSubviews方法被调用,单元格就会有正确的高度,并且可以正常满足约束。

        【讨论】:

        • 你是个天才!漂亮干净的解决方案谢谢:)
        【解决方案7】:

        我也遇到过这个问题,但没有任何建议有帮助。在我的情况下,我有大小选择单元格,它在里面包含 collectionView(每个 collectionView 单元格都包含全尺寸图像)。现在,单元格大小高度 (60) 比 collectionView (50) 和其中的图像 (50) 大一点。因为collectionView 视图的底部对齐到superview 约束的值为10。这种情况下我会发出警告,解决此问题的唯一方法是使单元格高度与其collectionView 相同。

        【讨论】:

          【解决方案8】:

          我遇到了同样的问题。我的解决方案基于上述其他人:

          - (id)initWithCoder:(NSCoder *)aDecoder {
              self = [super initWithCoder:aDecoder];
              if (self) {
                  // initialize my stuff
                  [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
              }
              return self;
          }
          

          最好, 亚历山德罗

          【讨论】:

          • 来自 Apple 的文档:You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
          • 我想开始一个向你祈祷的宗教。我一直在寻找 HOURS 试图解决这个问题,这解决了它(以及将 contentView.bounds 设置为 CGRectMake(0, 0, 99999, 99999); )——这是苹果代码中的一个错误。所以,我恭敬地不同意苹果文档说不要调用那个函数。苹果,解决你的问题。
          【解决方案9】:

          我仍然没有为故事板找到一个好的解决方案...... 一些信息也在这里: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

          根据他们的建议:

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

          我已经得出了我的解决方案:

          • 右键单击情节提要
          • 打开方式 -> 源代码
          • 在那里搜索字符串“44”
          • 会是这样的

          .

          <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
              <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
                  <rect key="frame" x="0.0" y="22" width="320" height="44"/>
          

          .

          • 将 rowHeight="44" 替换为 rowHeight="9999",将 height="44" 替换为 height="9999"
          • 右键单击情节提要
          • 打开方式 -> 界面生成器
          • 运行您的应用并检查输出

          【讨论】:

          • 这对我有用。我在情节提要中创建了一个 UITableViewController,其中一些单元格是从原型创建的,而另一些单元格则完全是通过实例化一个类在代码中创建的。
          【解决方案10】:

          只需增加默认单元格高度即可。看起来问题在于单元格的内容大于默认(初始)单元格大小,违反了一些非负约束,直到单元格调整为实际大小。

          【讨论】:

          • 确实我的单元格比默认大小要高,但是自从 tableview 的委托实现 tableView:heightForRowAtIndexPath: 以来,使用默认大小怎么会发生?
          • 可能会使用默认大小创建单元格,然后将其调整为实际大小。
          • 确实可以,但是为什么iOS6上没有呢?
          • @jafar iOS 7 对表格视图单元格进行了很多更改。在 iOS 7 上,表格视图单元格和 contentView 之间现在有一个滚动视图(UITableViewCellScrollView 类型);这可能解释了 iOS 6 和 7 之间的区别。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-04-06
          • 2013-09-29
          • 2018-07-06
          • 2016-02-04
          • 1970-01-01
          • 2013-10-01
          • 1970-01-01
          相关资源
          最近更新 更多