iOS 11:“无法同时满足约束”

Posted

技术标签:

【中文标题】iOS 11:“无法同时满足约束”【英文标题】:iOS 11: "Unable to simultaneously satisfy constraints" 【发布时间】:2018-02-09 12:51:01 【问题描述】:

总是跑到 FoodTracker 教程;遵循此步骤:“实现自定义控件”

https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiosAppsSwift/ImplementingACustomControl.html#//apple_ref/doc/uid/TP40015214-CH19-SW1

当执行第一个检查点时,模拟器显示一个红色矩形而不是教程中指示的正方形;在我得到的调试窗格上:

2018-02-09 11:19:42.130595+0100 FoodTracker[7439:80369] [MC] Lazy loading NSBundle MobileCoreServices.framework  
2018-02-09 11:19:42.131628+0100 FoodTracker[7439:80369] [MC] Loaded MobileCoreServices.framework  
2018-02-09 11:19:42.165143+0100 FoodTracker[7439:80369] [LayoutConstraints] 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.  
(  
    "<NSLayoutConstraint:0x60400028a3c0 UIButton:0x7f8a0bd0e330.width == 44   (active)>",  
    "<NSLayoutConstraint:0x60400028cda0 'UISV-canvas-connection' FoodTracker.RatingControl:0x7f8a0bd08890.leading == UIButton:0x7f8a0bd0e330.leading   (active)>",  
    "<NSLayoutConstraint:0x60400028ce40 'UISV-canvas-connection' H:[UIButton:0x7f8a0bd0e330]-(0)-|   (active, names: '|':FoodTracker.RatingControl:0x7f8a0bd08890 )>",  
    "<NSLayoutConstraint:0x60400028c940 'UIView-Encapsulated-Layout-Width' FoodTracker.RatingControl:0x7f8a0bd08890.width == 200   (active)>"  
)  

Will attempt to recover by breaking constraint  
<NSLayoutConstraint:0x60400028a3c0 UIButton:0x7f8a0bd0e330.width == 44   (active)>  

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.  
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.  
2018-02-09 11:19:42.165949+0100 FoodTracker[7439:80369] [LayoutConstraints] 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.  
(  
    "<NSLayoutConstraint:0x60400028a370 UIButton:0x7f8a0bd0e330.height == 44   (active)>",  
    "<NSLayoutConstraint:0x60400028a320 'UISV-canvas-connection' FoodTracker.RatingControl:0x7f8a0bd08890.top == UIButton:0x7f8a0bd0e330.top   (active)>",  
    "<NSLayoutConstraint:0x60400028cf30 'UISV-canvas-connection' V:[UIButton:0x7f8a0bd0e330]-(0)-|   (active, names: '|':FoodTracker.RatingControl:0x7f8a0bd08890 )>",  
    "<NSLayoutConstraint:0x60400028c990 'UIView-Encapsulated-Layout-Height' FoodTracker.RatingControl:0x7f8a0bd08890.height == 110   (active)>"  
)  

Will attempt to recover by breaking constraint  
<NSLayoutConstraint:0x60400028a370 UIButton:0x7f8a0bd0e330.height == 44   (active)>  

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.  
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.  

我认为以编程方式创建按钮并在此处应用自定义约束时会发生一些变化:(我正在使用 Swift 和 Xcode 9)

// Add constraints  
button.translatesAutoresizingMaskIntoConstraints = false  
button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true  
button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true  

欢迎任何解决问题的提示。

请注意,我正在构建一个自定义控件...我在谷歌上搜索到的所有注释似乎都不适用。

【问题讨论】:

What is NSLayoutConstraint "UIView-Encapsulated-Layout-Height" and how should I go about forcing it to recalculate cleanly?的可能重复 @the4kman - 不幸的是没有……已经研究过了。请注意,Button 控件是通过编程方式创建的。 与我们分享您的代码 @MilanNosáľ - 认为这是一个完整的 Xcode 项目;可以在指定的链接中找到一份好的简历,而不会有错过发布重要内容的风险;我认为将按钮设置为 44 x 44 与视图中预定义的常量相冲突。例如,可以通过编程将宽度和高度约束优先级设置为 1001? 看起来您正在将按钮的边缘约束到其他元素,但随后您也试图约束宽度和高度。如果边缘最终不能准确地提供宽度和高度值,那将不起作用。 【参考方案1】:

结语

问题自己消失了。

继续练习,Xcode IDE 强调了视图设计中的一些关键点,我被邀请“单击图标”进行修复;其中一个问题与冲突的约束有关。

正如#DonMag 所建议的,RatingControl 类必须标记为@IBDesignable(这个装饰器将在后面的练习中添加)让 Xcode 立即查看自定义控件的最终结果。几乎:星星没有出现,并且控件不会自动缩放将星星添加到控件属性。直到我关闭,再次打开并重建整个项目几次。

教程(为 Swift 3.2 编写)和实际 Xcode(适用于 Swift 4 中打开的默认项目)的差异。

我的想法是,Apple 必须更新它自己的在线文档,以避免人们在试图弄清楚为什么事情没有像预期的那样工作时失去理智。

【讨论】:

【参考方案2】:

忽略我的前两个 cmets...

在该教程中,您将添加自定义 ratingControl 作为垂直堆栈视图的排列子视图。这就是不需要约束的原因。

关键是创建类@IBDesignable - 允许Interface Builder 和自动布局引擎使用类的固有大小 来正确调整大小/定位/显示它。

(有点奇怪,教程中没有注明。)

【讨论】:

你指的是RatingControl类吗?我已经测试过了,还是不行……:-( 您是否创建了 RatingControl 课程 @IBDesignable?所以你的红色按钮出现在 Storyboard / Interface Builder 中? 是的,RatingControl 类是 @IBDesignable,但故事板中没有显示按钮! ...显然按钮仍然是一个填充子视图的矩形。【参考方案3】:

我有同样的问题。 此外,红色方块看起来比教程中显示的要大。 为了让红色方块接受大小为 44 的约束,我必须确保 RatingControl 位于堆栈视图内部,而不是下方。

我附上图片以澄清我所说的“在堆栈视图中”的意思。

error reproduced, please note red rectangle outside the stack view hierarchy

error fixed, the red rectangle is inside the stack view hierarchy on the left

【讨论】:

【参考方案4】:

问题是因为所有子视图的总宽度不等于 StackView 的宽度。

使用这个计算可以解决问题:

let width = (self.frame.width - self.spacing * CGFloat(starCount-1))/CGFloat(starCount)
let height = self.frame.height

............

for _ in 0..<starCount 
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.red
        button.heightAnchor.constraint(equalToConstant: height).isActive = true
        button.widthAnchor.constraint(equalToConstant: width).isActive = true
        button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(button:)), for: .touchUpInside)
        addArrangedSubview(button)
    

【讨论】:

以上是关于iOS 11:“无法同时满足约束”的主要内容,如果未能解决你的问题,请参考以下文章

iOS - AutoLayout'无法同时满足约束'

iOS:无法同时满足约束

无法同时满足约束 iOS

如果设置隐藏,iOS UIStackView 无法同时满足约束

iOS 8 自定义键盘:更改高度而不发出警告“无法同时满足约束...”

UITableViewCell - 无法同时满足约束