【问题标题】:Auto-layout: What creates constraints named UIView-Encapsulated-Layout-Width & Height?自动布局:是什么创建了名为 UIView-Encapsulated-Layout-Width & Height 的约束?
【发布时间】:2014-06-12 01:40:48
【问题描述】:

我的布局约束在 Interface Builder 中很好,但由于框架的某些部分应用了我真的不想要的固定高度和宽度约束,所以在运行时发生异常。它们为什么存在,以及如何关闭它们?

它们是记录列表中显示的最后两个约束:

2014-04-26 09:02:58.687 BBCNews[32058:60b] 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:0xbf478a0 UIView:0xbf4a3c0.height == 0.28125*UIView:0xbf4a3c0.width>",
    "<NSLayoutConstraint:0xbf47190 UIView:0xbf4a3c0.leading == BNMyNewsCell_landscape:0xbf48b10.leading>",
    "<NSLayoutConstraint:0xbf47160 UIView:0xbf4a3c0.trailing == BNMyNewsCell_landscape:0xbf48b10.trailing>",
    "<NSLayoutConstraint:0xbf47130 BNMyNewsCell_landscape:0xbf48b10.bottom == UIView:0xbf4a3c0.bottom>",
    "<NSLayoutConstraint:0xbf47100 UIView:0xbf4a3c0.top == BNMyNewsCell_landscape:0xbf48b10.top>",
    "<NSLayoutConstraint:0xd4c3c40 'UIView-Encapsulated-Layout-Width' H:[BNMyNewsCell_landscape:0xbf48b10(304)]>",
    "<NSLayoutConstraint:0xd4c38a0 'UIView-Encapsulated-Layout-Height' V:[BNMyNewsCell_landscape:0xbf48b10(290)]>"
}
Will attempt to recover by breaking constraint 

<NSLayoutConstraint:0xbf478a0 UIView:0xbf4a3c0.height == 0.28125*UIView:0xbf4a3c0.width>

【问题讨论】:

    标签: ios uitableview uicollectionview autolayout


    【解决方案1】:

    UIView-Encapsulated-Layout-* 是表、集合和堆栈对布局元素使用的约束,正如您告诉他们这样做的那样。如果您稍后设置了导致大小更改的约束,您将遇到冲突。此用例的一个示例是下载可变大小图像的单元格。

    发生这种情况是因为我们习惯于使用 layoutIfNeeded() 来刷新布局,但是一旦集合通过渲染周期,单元格大小就会通过封装的约束来设置。您需要手动使需要刷新的索引路径失效,例如

    let context = UICollectionViewLayoutInvalidationContext()
    context.invalidateItems(at: [cellIndexPath])
    collectionView.collectionViewLayout.invalidateLayout(with: context)
    

    这将递归地创建更多的失效来移动其他单元格的位置并腾出空间。

    如果您设置,例如一个不同的高度约束来改变单元格的大小,它会立即崩溃,然后在您无效并且单元格再次布局后恢复。为了避免这种崩溃,您可以将高度约束的优先级降低到低于.required,例如 UILayoutPriority(999)。

    【讨论】:

    【解决方案2】:

    敲了一会儿我的头后,我找到了this link。就我而言,当我使用 UIVieController 中的 insertRows 或 deleteRows 时,它发生在 UITableViewHeaderFooterView 上。 'estimatedSectionHeaderHeight' 和 'estimatedRowHeight' 在哪里设置,我的约束重做 3 次......显示的错误是:

    "<NSLayoutConstraint:0x280648140 H:|-(8)-[UIImageView:0x106e94860]   (active, names: '|':DAT_Air_Vinyl.ExportsAlbumTableViewHeader:0x106e8fb50 )>",
    "<NSLayoutConstraint:0x280648230 H:[UIImageView:0x106e94860]-(8)-[DAT_Air_Vinyl.MainLabel:0x106ea5750'The Coral - The Invisible...']   (active)>",
    "<NSLayoutConstraint:0x280648410 H:[UIButton:0x106ea5a40]-(8)-|   (active, names: '|':DAT_Air_Vinyl.ExportsAlbumTableViewHeader:0x106e8fb50 )>",
    "<NSLayoutConstraint:0x280648460 H:[DAT_Air_Vinyl.MainLabel:0x106ea5750'The Coral - The Invisible...']-(8)-[UIButton:0x106ea5a40]   (active)>",
    "<NSLayoutConstraint:0x2806493b0 'UIView-Encapsulated-Layout-Width' DAT_Air_Vinyl.ExportsAlbumTableViewHeader:0x106e8fb50.width == 0   (active)>"
    

    如链接所述:

    "当你对某些动画类型执行 insertRows 或 deleteRows 时,UIKit 会将行高从 0 设置为全高或返回。在该动画的 0 端,如果整个垂直轴设置为优先级 = 1000。但仅将一个约束降低到 999 - 假设底部空间到超级视图边距 - 一切都很好;内容将只是下拉,超出单元格的边界。"。

    解决方案是将 UIImageView 的首要优先级设置为 999(或低于 1000)。

    【讨论】:

      【解决方案3】:

      我终于找到了 CollectionView 的解决方案!如果你像我一样使用storyBoard,它会对你有所帮助!

      界面构建器/故事板

      转到 storyBoard -> 选择您的 CollectionView ScreenShot CollectionView 转到尺寸检查器 然后将 Estimate Size 设置为 None ScreenShot Estimate Size

      就是这样!

      【讨论】:

        【解决方案4】:

        我遇到了类似的问题,并通过以下方式解决了它。

        • 环境: Swift 5.0,xcode 10.2.1,以编程方式设置视图

        • 警告消息: 无法同时满足约束... 'UIView-Encapsulated-Layout-Width' UIView:0x0000000000.width == 0 (active)>" )

        • 带有警告的代码

          override func loadView() {
          
          view = UIView()
          
          /// Adds the subviews to the view and sets their properties and constraints
          setupViews()
          
          }
          
        • 清除警告的代码

          override func loadView() {
          
          /// Needed to set the frame of the root view to the window frame.
          let window = UIWindow()
          view = UIView(frame: window.frame)
          
          /// Adds the subviews to the view and sets their properties and constraints
          setupViews()
          }
          
        • loadView()方法注意事项: "如果你使用Interface Builder创建你的视图并初始化视图控制器,你不能重写这个方法。你可以重写这个方法在为了手动创建视图。如果您选择这样做,请将视图层次结构的根视图分配给视图属性。您创建的视图应该是唯一的实例,并且不应与任何其他视图控制器对象共享。您的自定义实现这个方法不应该调用super。” - 苹果文档

        • 根视图的注意事项:

          “如果您更喜欢以编程方式创建视图...您可以通过覆盖来实现 你的视图控制器的 loadView 方法。您对此方法的实现 应该做到以下几点:

          创建一个根视图对象。根视图包含所有其他关联的视图 与您的视图控制器。您通常将此视图的框架定义为 匹配应用程序窗口的大小,它本身应该填满屏幕。然而, 框架会根据视图控制器的显示方式进行调整。请参阅“查看 控制器视图调整大小。”

          您可以使用通用 UIView 对象、您定义的自定义视图或任何其他 可以缩放以填满屏幕的视图。

          创建额外的子视图并将它们添加到根视图。” - 老苹果 文档?

        【讨论】:

          【解决方案5】:

          约束UIView-Encapsulated-Layout-Height 是使用您在tableView.estimatedSectionHeaderHeight 中设置的值创建的

          【讨论】:

            【解决方案6】:

            我在使用 AL create tableviewHeader 时遇到了这个问题

            我像下面这样初始化表格视图

            let table = UITableView.init(frame: .zero, style: .grouped)
            // set table constraint ...
            

            然后我使用 AutoLayout 创建 tableviewHeader。

            "&lt;NSLayoutConstraint:0x600003d7d130 'UIView-Encapsulated-Layout-Width' UIView:0x7fe92bc55260.width == 0 (active)&gt;"

            符号断点出现

            在我参考@Yerk 的答案后。 我在初始化 tableView 时更改了框架

            let rect = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: 0)
            let table = UITableView.init(frame:rect , style: .grouped)
            

            问题似乎解决了

            【讨论】:

              【解决方案7】:

              就我而言,我无意中设置了两次编程约束。一旦我删除了重复调用,冲突就消失了。

              【讨论】:

                【解决方案8】:

                我们已经开始在 iOS 11 中看到大量的布局冲突,其中包括对这些约束的引用,它们实际上是通过 translatesAutoresizingMaskIntoConstraints 标志添加的。似乎在 iOS 11 中,当视图被添加到层次结构时会发生更多的 AutoLayout 魔法,而不仅仅是在布局视图时(因为它似乎在以前的 iOS 版本中工作)。

                这是我们遇到的情况:

                • 创建一个视图,其内部布局有助于定义视图大小(例如,视图具有包含显式填充等的内部约束)
                • *** 将此视图添加到层​​次结构中。
                • 稍后,在布局传递之前,将 translatesAutoresizingMaskIntoConstraints 设置为 false。

                第二步 (***) 将导致冲突,因为系统会在视图添加到层​​次结构时向视图添加零大小约束。由于使用了 PureLayout 框架,我们稍后设置了translatesAutoresizingMaskIntoConstraints,该框架会在您约束视图时自动正确设置此标志...也就是说,在 iOS 11 中,您需要记住在构建时关闭 translatesAutoresizingMaskIntoConstraints,之前视图被添加到层次结构中。

                我怀疑 Apple 认为将此标志默认为 YES 会比痛苦更有用。不幸的是,情况并非如此。

                【讨论】:

                • PureLayout 提供 initForAutoLayoutnewAutoLayoutView 初始化器,将 translatesAutoresizingMaskIntoConstraints 设置为 false,可以在 ALView 子类上调用
                【解决方案9】:

                向表格视图标题添加约束时,我遇到了同样的问题。当标头的边界为 (0,0,0,0) 时,似乎会在使用设置常量添加约束时发生。当标题的边界不是(0,0,0,0)时,我设法通过仅在布局子视图方法中添加约束来解决此问题

                    if self.bounds == CGRect.zero {
                        return
                    }
                

                【讨论】:

                  【解决方案10】:

                  我遇到了同样奇怪的限制,不知道为什么,直到我想起了该死的 translatesAutoresizingMaskIntoConstraints 属性。将此设置为false 解决了这个问题。 在后台发生的事情是自动调整大小的掩码(iOS 的旧布局引擎)被转换为约束。很多时候,您不想要这些约束,而是想要自己的约束。在这种情况下,您应该将此属性设置为 false,这样就可以了:

                  view.translatesAutoresizingMaskIntoConstraints = false
                  

                  【讨论】:

                  • 您在哪个view 上设置了这个?是 UITableViewCell 吗?
                  • 您通常将其设置在您要添加的视图上。
                  【解决方案11】:

                  我在 iPad Pro 上测试拆分视图时发现了类似的问题,并且 DesignatedNerd 的答案有效,但我不需要这么多代码。这是我使用的:

                  [self.tableView.tableHeaderView setTranslatesAutoresizingMaskIntoConstraints:NO];
                  
                  NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.myTableHeaderView
                                                                                     attribute:NSLayoutAttributeWidth
                                                                                     relatedBy:NSLayoutRelationEqual
                                                                                        toItem:self.tableView
                                                                                     attribute:NSLayoutAttributeWidth
                                                                                    multiplier:1
                                                                                      constant:0];
                  NSLayoutConstraint *yConstraint = [NSLayoutConstraint constraintWithItem:self.myTableHeaderView
                                                                                 attribute:NSLayoutAttributeTop
                                                                                 relatedBy:NSLayoutRelationEqual
                                                                                    toItem:self.tableView
                                                                                 attribute:NSLayoutAttributeTop
                                                                                multiplier:1
                                                                                  constant:0];
                  
                  
                  [self.tableView addConstraints:@[widthConstraint, yConstraint]];
                  

                  注意添加了 Y 约束,它将 tableHeaderView 的顶部绑定到 tableView 的顶部。

                  【讨论】:

                    【解决方案12】:

                    肯定会在UITableViewtableHeaderView 上看到这个。在设置tableHeaderView 之后,通过显式设置宽度等于tableView 的宽度,我能够使其与自定义标题视图一起使用,然后在布局传递完成后重置它。

                    iOS 9 的示例代码,假设您将 UITableView 作为 tableView 传递到您的方法中,并将其配置为 item 的项目:

                    //Create the header view
                    self.contentDetailHeaderView = MyCustomHeaderView()
                    
                    //Turn on autolayout
                    self.contentDetailHeaderView.translatesAutoresizingMaskIntoConstraints = false
                    
                    //Add the header to the table view
                    tableView.tableHeaderView = self.contentDetailHeaderView
                    
                    //Pin the width  
                    let widthConstraint = NSLayoutConstraint(item: self.contentDetailHeaderView,
                        attribute: .Width,
                        relatedBy: .Equal,
                        toItem: tableView,
                        attribute: .Width,
                        multiplier: 1,
                        constant: 0)
                    
                    tableView.addConstraint(widthConstraint)
                    
                    //Do whatever configuration you need to - this is just a convenience method I wrote on my header view.
                    self.contentDetailHeaderView.setupForItem(item)
                    
                    //Lay out the configured view
                    self.contentDetailHeaderView.layoutIfNeeded()
                    
                    //Reset the table header view, because ¯\_(ツ)_/¯
                    tableView.tableHeaderView = self.contentDetailHeaderView
                    

                    几条笔记,主要是因为我有金鱼的记忆而再次查找此内容时:

                    • 您确实必须从viewDidLayoutSubviews 调用它 - 只要tableView 在设置期间具有适当的宽度,我就能够使用此技术。
                    • 您确实需要确保您的标题视图设置为自动调整大小。为此,我创建了一个 .xib,然后确保所有项目都已固定,这样当视图更改宽度时,高度也会随之更新。
                    • 如果您尝试为viewForHeaderInSection 执行此操作,您最好在屏幕外抓取一些可以布置为this technique 的东西。我对自我调整大小的钻头不太走运。

                    【讨论】:

                    • 哇。经过半小时的混乱......这确实有效!我不明白为什么需要它,但它有效。很糟糕,我们必须这样做。
                    【解决方案13】:

                    我在各种情况下都遇到了这个错误(不一定与correct 答案所建议的 UICollectionView 和朋友有关)..

                    所以我处理它的方法是简单地清除所有约束然后重新构建它们(只是这次我不担心我的约束与这些预先创建的约束发生冲突):

                    所以在代码中:

                    UIView *parentView = [viewInQuestion superview];
                    [parentView clearConstraintsOfSubview:viewInQuestion];
                    

                    clearConstraintsOfSubview 是 UIView 上的类别方法:

                    - (void)clearConstraintsOfSubview:(UIView *)subview
                    {
                        for (NSLayoutConstraint *constraint in [self constraints]) {
                            if ([[constraint firstItem] isEqual:subview] || [[constraint secondItem] isEqual:subview]) {
                                [self removeConstraint:constraint];
                            }
                        }
                    }
                    

                    【讨论】:

                      【解决方案14】:

                      基于大量观察,我相信(但不能确定)名为 UIView-Encapsulated-Layout-WidthUIView-Encapsulated-Layout-Height 的约束是由 UICollectionView 和朋友创建的,并且存在以强制执行 sizeForItemAtIndexPath 返回的大小委托方法。我想这是为了确保cellForItemAtIndexPath 设置的UICollectionViewCell 最终达到它被告知的大小。

                      这回答了我最初的问题。第二个问题是为什么约束不能满足?单元格的固有高度应该与UIView-Encapsulated-Layout-Height 相同。同样,我不确定,但我怀疑这是一个舍入错误(即固有高度达到 200.1 像素,UIView-Encapsulated-Layout-Height 可能舍入到 200。我想出的解决方法是降低优先级相关的单元格约束以允许 UIView-Encapsulated-Layout-Height 拥有最后一句话。

                      【讨论】:

                      • 美丽。修复了我的项目中的一个类似问题。
                      • 这修复了我的约束破坏和相应的警告消息,但现在我的文本视图已折叠,直到我将单元格滚动出视图然后再返回。
                      • @Alex311 您是否尝试在 IB 中调整压缩阻力(或其他名称)?我发现增加这个值有助于防止文本折叠
                      • 只是补充一点,我在 8.3 设备中遇到了与 UIView-Encapsulated-Layout-Width 类似的问题,并记得 this tweet。致电[someView layoutIfNeeded] 帮助解决了问题。
                      • 我完全希望在控制台中修复约束警告,但不知何故,我遇到了另一个约束问题,导致我进入此页面,我很高兴来到这里并看到你的答案。我只是将优先级降低到 999,然后繁荣,我所有的约束警告都消失了 :) 非常感谢 :) :) :)
                      【解决方案15】:

                      这可能无法回答您的问题,但它可以帮助像我这样通过搜索来到这里的其他人。

                      我收到了一个奇怪的 AutoLayout 破坏约束错误,并伴有 UIView-Encapsulated-Layout-Width 约束,因为我正在将 tableHeaderView 添加到尚未使用 AutoLayout 调整大小的表视图中。所以系统试图将我的标题子视图的约束应用到一个带有{0,0,0,0} 框架的表视图中。由于 UITableView 喜欢控制其元素的宽度,因此其生成的宽度约束 UIView-Encapsulated-Layout-Width 被设置为零,导致与我的预期宽度为 320+pt 的标题元素产生各种混淆。

                      要点:确保在自动布局调整表格视图的大小后添加/操作补充/页眉/页脚视图。

                      【讨论】:

                      • 我想确保我这样做是正确的。你能解释一下如何确定这些操作发生在 AutoLayout 之后吗?
                      • @nwales 当 iOS 尝试在 0 x 0 视图内布局约束时,就会出现问题。为避免此错误,只需确保容器视图(在我的情况下为 tableHeaderView)已布局或手动调整大小。您可以通过在设置约束之前使用近似大小初始化容器视图来做到这一点,或者如果您想要纯自动布局 - 布局容器视图的约束,然后在设置子视图约束之前调用[thatContainer layoutIfNeeded]。如果您没有收到错误并且您的观点是正确的,那么您无需担心。
                      • 谢谢!翻转我布局表格视图并分配其标题的顺序使此错误消失=)
                      • 最好的解决方案是放弃约束的优先级,这样它们就不需要了。放弃高工作的优先级。
                      猜你喜欢
                      • 2015-10-09
                      • 2021-01-14
                      • 2014-02-05
                      • 2021-05-21
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-04-09
                      • 2016-03-04
                      • 2015-06-16
                      相关资源
                      最近更新 更多