自动布局:创建名为UIView-Encapsulated-Layout-Width&高度?

时间:2014-04-26 08:13:44

标签: ios uitableview uicollectionview autolayout

我的界面约束在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>

14 个答案:

答案 0 :(得分:87)

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

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

答案 1 :(得分:42)

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

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

内容:确保在通过AutoLayout调整tableview后,添加/操作补充/页眉/页脚视图。

答案 2 :(得分:5)

我面对着同样奇怪的约束而且不知道为什么,直到我记得那个愚蠢的translatesAutoresizingMaskIntoConstraints属性。将此设置为false解决了问题。 后台发生的事情是自动调整大小掩码(iOS的旧布局引擎)转换为约束。通常,您不需要这些约束并且想要自己的约束。在这种情况下,你应该将此属性设置为false,你会没事的:

view.translatesAutoresizingMaskIntoConstraints = false

答案 3 :(得分:4)

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

这是我们遇到的情况:

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

第二步(***)将导致冲突,因为系统将在将视图添加到层​​次结构时向视图添加零大小约束。我们之后使用PureLayout框架设置了translatesAutoresizingMaskIntoConstraints,当你约束视图时,它会自动正确地设置这个标志......那就是说,在iOS 11中你需要记住关闭translatesAutoresizingMaskIntoConstraints at构造时间,在视图添加到层​​次结构之前。

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

答案 4 :(得分:3)

我在各种情况下都遇到了这个错误(不一定与这里的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];
        }
    }
}

答案 5 :(得分:2)

绝对可以在UITableView tableHeaderView上看到这一点。通过在设置tableView之后显式设置宽度等于tableHeaderView的宽度,然后在布局传递完成后重置它,我能够使用自定义标题视图。

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执行此操作,那么您可能最好在屏幕外抓取一些可以布置la this technique的内容。我对自我调整的位数没什么好运。

答案 6 :(得分:1)

就我而言,我无意中两次设置了程序性约束。一旦我删除了重复的电话,冲突就消失了。

答案 7 :(得分:1)

使用AL创建tableviewHeader时遇到了这个问题

我像下面这样初始化tableview

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

然后使用AutoLayout创建tableviewHeader。

"<NSLayoutConstraint:0x600003d7d130 'UIView-Encapsulated-Layout-Width' UIView:0x7fe92bc55260.width == 0 (active)>"

出现符号断点

在我引用@Yerk的答案之后。 我初始化tableView时会更改框架

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

问题似乎已经解决

答案 8 :(得分:1)

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

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

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

  • 带有警告的代码

    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创建视图并初始化视图控制器,则不能覆盖此方法。可以在为了手动创建视图,如果选择这样做,则将视图层次结构的根视图分配给view属性,创建的视图应该是唯一的实例,并且不应与任何其他视图控制器对象共享。这种方法的调用不应称为超级。” -Apple文档

  • 关于根视图的注释:

    ”“如果您希望通过编程方式创建视图,则可以通过重写来实现 您的视图控制器的loadView方法。您对此方法的实现 应该执行以下操作:

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

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

    创建其他子视图并将其添加到根视图。”-老苹果 文档?

答案 9 :(得分:1)

最后,我找到了CollectionView的解决方案!如果您像我一样使用storyBoard,它将为您提供帮助!

SWIFT

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

就这些!

答案 10 :(得分:0)

我在iPad Pro上测试Split View时发现了类似的问题,并且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 Constraint,它将tableHeaderView的顶部绑定到tableView的顶部。

答案 11 :(得分:0)

向表视图标题添加约束时遇到了同样的问题。当标题的边界为(0,0,0,0)时,在使用set constants添加约束时似乎会发生这种情况。我设法解决这个问题,只是当标题的边界不是(0,0,0,0)时,只在布局子视图方法中添加约束

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

答案 12 :(得分:0)

使用您在#Create Dataset x <- c(1,1,4,4,9) #Estimate Density d <- density(x) #Two ways to get highest Peak d$x[d$y==max(d$y)] #Gives you all highest Peaks d$x[which.max(d$y)] #Gives you the first highest Peak #3 ways to get all Peaks d$x[c(F, diff(diff(d$y)>=0)<0)] #This detects also a plateau d$x[c(F, diff(sign(diff(d$y)))<0)] d$x[which(diff(sign(diff(d$y)))<0)+1] #In case you also want the height of the peaks data.frame(d[c("x", "y")])[c(F, diff(diff(d$y)>=0)<0),] #In case you need a higher "precision" d <- density(x, n=1e4) 中设置的值创建

约束UIView-Encapsulated-Layout-Height

答案 13 :(得分:0)

敲了一下头后,我发现this link。就我而言,这是在我使用UIVieController中的insertRows或deleteRows时在UITableViewHeaderFooterView上发生的。设置了“ estimatedSectionHeaderHeight”和“ estimatedRowHeight”,我的约束重做了3次...显示的错误是:

<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>
  </div>
</div>
<script type="text/javascript">

function myFunction() {
    // Check if dropdown is open
    const isOpen = document.getElementById('myDropdown').style.display=='block';

    // if dropdown is closed, perform some actions
    if (!isOpen) {
       // your code here...
    }

    // Code that actually opens or closes the dropdown, switch a style for example
    document.getElementById('myDropdown').style.display = isOpen ? 'none' : 'block';
}

</script>

如链接中所述:

当您对某些动画类型执行insertRows或deleteRows时,UIKit将使行高从0到全高或向后移动。在该动画的0端,布局方程式无法求解垂直轴设置为priority = 1000。但是将一个约束降低到999(例如,底部空间到超级视图边距),一切都很好;内容将在单元格的边界之外下拉。”。< / p>

解决方案是将UIImageView的前导优先级设置为999(或降低到1000)。