如何解决:无法同时满足约束

Posted

技术标签:

【中文标题】如何解决:无法同时满足约束【英文标题】:How to resolve : Unable to simultaneously satisfy constraints 【发布时间】:2018-01-12 11:15:57 【问题描述】:

我想这样创作(通过故事板完成)

这通过故事板完成。在我的观察中,我发现约束问题来自"totalAmountImg"。我不会更改所有对象的优先级属性(所有对象都有优先级 == 1000)

这就是结果。 (SummaryVC - 以编程方式完成)

注意:我想让 SummaryVC totalAmountImg(以编程方式)看起来像上图(由故事板制作)

totalAmountImg 的故事板约束

这正是我通过代码创建的。但是我不知道为什么会弹出这个错误。

totalImgConstraint

func totalAmountImgConstraints() 
        let imgCenterY = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .centerY,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .centerY,
                           multiplier: 1.0,
                           constant: 0)
        imgCenterY.identifier = "imgCenterY"
        imgCenterY.isActive = true

        let imgRight = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .right,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .right,
                           multiplier: 1.0,
                           constant: 16)
        imgRight.identifier = "imgRight"
        imgRight.isActive = true

        let imgAspectRatio = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: totalAmountImg,
                           attribute: .width,
                           multiplier: 1.0 / 1.0,
                           constant: 0)
        imgAspectRatio.identifier = "imgAspectRatio"
        imgAspectRatio.isActive = true

        let imgLeft = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .left,
                           relatedBy: .equal,
                           toItem: totalPriceLbl,
                           attribute: .right,
                           multiplier: 1.0,
                           constant: 4)
        imgLeft.identifier = "imgLeft"
        imgLeft.isActive = true

        let imgWidth = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .width,
                           relatedBy: .lessThanOrEqual,
                           toItem: totalAmountView,
                           attribute: .width,
                           multiplier: 0.2,
                           constant: 0)
        imgWidth.identifier = "imgWidth"
        imgWidth.isActive = true
    

总结VC

class SummaryVC: UIViewController, UIScrollViewDelegate 

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var pageController: UIPageControl!

    let numberOfPages = 3

    override func viewDidLoad() 
        super.viewDidLoad()
        basicDesignSetup()

        // Add subViews
        scrollView.addSubview(summaryBaseView)
        scrollView.addSubview(paymentTypeBaseView)
        scrollView.addSubview(itemNameBaseView)

        summaryBaseView.addSubview(totalAmountView)
        summaryBaseView.addSubview(runningTableView)
        summaryBaseView.addSubview(partnerAmountView)

        totalAmountView.addSubview(totalLbl)
        totalAmountView.addSubview(totalPriceLbl)
        totalAmountView.addSubview(totalAmountImg)


        view.setNeedsUpdateConstraints()

        // set content size
        scrollView.contentSize = CGSize(width: scrollView.frame.width * CGFloat(numberOfPages), height: scrollView.frame.height)
    

    override func viewDidLayoutSubviews() 

    

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) 
        let pageNumber = scrollView.contentOffset.x / scrollView.frame.width
        pageController.currentPage = Int(pageNumber)
        pageController.currentPageIndicatorTintColor = UIColor.white
    

    //-----------------------------------------------------------------
    // MARK: - Methods
    //-----------------------------------------------------------------

    func basicDesignSetup() 
        pageController.numberOfPages = numberOfPages
        let scrollViewSize = scrollView.frame.size
        let scrollViewWidth = scrollView.frame.width

        // Summary View
        let summeryOrigin = CGPoint(x: 0, y: 0)
        summaryBaseView = UIView(frame: CGRect(origin: summeryOrigin, size: scrollViewSize))
        summaryBaseView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)

        // Payment Type View
        let paymentTypeOrigin = CGPoint(x: scrollViewWidth, y: 0)
        paymentTypeBaseView = UIView(frame: CGRect(origin: paymentTypeOrigin, size: scrollViewSize))
        paymentTypeBaseView.backgroundColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 1)

        // Item Name View
        let itemNameOrigin = CGPoint(x: scrollViewWidth * 2, y: 0)
        itemNameBaseView = UIView(frame: CGRect(origin: itemNameOrigin, size: scrollViewSize))
        itemNameBaseView.backgroundColor = #colorLiteral(red: 0, green: 0.9914394021, blue: 1, alpha: 1)

        // Total Amount View
        totalAmountView.backgroundColor = #colorLiteral(red: 0.5480614305, green: 0.8129847646, blue: 0.6160266995, alpha: 1)
        runningTableView.backgroundColor = #colorLiteral(red: 0.4280827343, green: 0.7700845003, blue: 0.9571052194, alpha: 1)
        partnerAmountView.backgroundColor = #colorLiteral(red: 0.9137254902, green: 0.4470588235, blue: 0.4549019608, alpha: 1)

        totalLbl.text = "Total Amount"
        totalLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        totalLbl.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
        totalLbl.font = UIFont.systemFont(ofSize: 16, weight: .medium)

        totalPriceLbl.text = "5532.00"
        totalPriceLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        totalPriceLbl.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)

        totalAmountImg.contentMode = .scaleAspectFit
        totalAmountImg.image = #imageLiteral(resourceName: "tick")
        totalAmountImg.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

    


    //-----------------------------------------------------------------
    // MARK: - Views - programatically
    //-----------------------------------------------------------------

    // Base Views
    lazy var summaryBaseView: UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    lazy var paymentTypeBaseView: UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    lazy var itemNameBaseView: UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    // $$$$$ Summary Sub Views $$$$$

    // Total Amount
    lazy var totalAmountView: UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    lazy var totalLbl: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    lazy var totalPriceLbl: UnderlinedLabel = 
        let label = UnderlinedLabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    lazy var totalAmountImg: UIImageView = 
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    ()

    // Running Table
    lazy var runningTableView: UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    lazy var runningLbl: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    lazy var runningPriceLbl: UnderlinedLabel = 
        let label = UnderlinedLabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    lazy var runningTableImg: UIImageView = 
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    ()

    // Partner Amount
    lazy var partnerAmountView: UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    lazy var partnerLbl: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    lazy var partnerPriceLbl: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()

    lazy var partnerAmountImg: UIImageView = 
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    ()



    //-----------------------------------------------------------------
    // MARK: - Constraints
    //-----------------------------------------------------------------

    override func updateViewConstraints() 
        totalAmountViewConstraints()
        runningTableViewConstraints()
        partnerAmountViewConstraints()

        // Total Amount View
        totalLblConstraint()
        totalPriceLblConstraints()
        totalAmountImgConstraints()

        super.updateViewConstraints()
    

    func totalAmountViewConstraints() 
        NSLayoutConstraint(item: totalAmountView,
                           attribute: .left,
                           relatedBy: .equal,
                           toItem: summaryBaseView,
                           attribute: .left,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalAmountView,
                           attribute: .right,
                           relatedBy: .equal,
                           toItem: summaryBaseView,
                           attribute: .right,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalAmountView,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: summaryBaseView,
                           attribute: .top,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalAmountView,
                           attribute: .bottom,
                           relatedBy: .equal,
                           toItem: runningTableView,
                           attribute: .top,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalAmountView,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: runningTableView,
                           attribute: .height,
                           multiplier: 1.0,
                           constant: 0).isActive = true
    

    func runningTableViewConstraints() 
        NSLayoutConstraint(item: runningTableView,
                           attribute: .leading,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .leading,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: runningTableView,
                           attribute: .trailing,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .trailing,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: runningTableView,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .bottom,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: runningTableView,
                           attribute: .bottom,
                           relatedBy: .equal,
                           toItem: partnerAmountView,
                           attribute: .top,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: runningTableView,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .height,
                           multiplier: 1.0,
                           constant: 0).isActive = true
    

    func partnerAmountViewConstraints() 
        NSLayoutConstraint(item: partnerAmountView,
                           attribute: .leading,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .leading,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: partnerAmountView,
                           attribute: .trailing,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .trailing,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: partnerAmountView,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: runningTableView,
                           attribute: .bottom,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: partnerAmountView,
                           attribute: .bottom,
                           relatedBy: .equal,
                           toItem: summaryBaseView,
                           attribute: .bottom,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: partnerAmountView,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .height,
                           multiplier: 1.0,
                           constant: 0).isActive = true
    

    // Total Ammount Section Subviews
    func totalLblConstraint() 
        NSLayoutConstraint(item: totalLbl,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .top,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalLbl,
                           attribute: .left,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .left,
                           multiplier: 1.0,
                           constant: 16).isActive = true

        NSLayoutConstraint(item: totalLbl,
                           attribute: .bottom,
                           relatedBy: .equal,
                           toItem: totalPriceLbl,
                           attribute: .top,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalLbl,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: totalPriceLbl,
                           attribute: .height,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalLbl,
                           attribute: .width,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .width,
                           multiplier: 0.7,
                           constant: 0).isActive = true
    

    func totalPriceLblConstraints() 
        NSLayoutConstraint(item: totalPriceLbl,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: totalLbl,
                           attribute: .bottom,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalPriceLbl,
                           attribute: .leading,
                           relatedBy: .equal,
                           toItem: totalLbl,
                           attribute: .leading,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalPriceLbl,
                           attribute: .bottom,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .bottom,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalPriceLbl,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: totalLbl,
                           attribute: .height,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalPriceLbl,
                           attribute: .width,
                           relatedBy: .equal,
                           toItem: totalLbl,
                           attribute: .width,
                           multiplier: 1.0,
                           constant: 0).isActive = true

        NSLayoutConstraint(item: totalPriceLbl,
                           attribute: .trailing,
                           relatedBy: .equal,
                           toItem: totalLbl,
                           attribute: .trailing,
                           multiplier: 1.0,
                           constant: 0).isActive = true
    

    func totalAmountImgConstraints() 
        let imgCenterY = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .centerY,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .centerY,
                           multiplier: 1.0,
                           constant: 0)
        imgCenterY.identifier = "imgCenterY"
        imgCenterY.isActive = true

        let imgRight = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .right,
                           relatedBy: .equal,
                           toItem: totalAmountView,
                           attribute: .right,
                           multiplier: 1.0,
                           constant: 16)
        imgRight.identifier = "imgRight"
        imgRight.isActive = true

        let imgAspectRatio = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: totalAmountImg,
                           attribute: .width,
                           multiplier: 1.0 / 1.0,
                           constant: 0)
        imgAspectRatio.identifier = "imgAspectRatio"
        imgAspectRatio.isActive = true

        let imgLeft = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .left,
                           relatedBy: .equal,
                           toItem: totalPriceLbl,
                           attribute: .right,
                           multiplier: 1.0,
                           constant: 4)
        imgLeft.identifier = "imgLeft"
        imgLeft.isActive = true

        let imgWidth = NSLayoutConstraint(item: totalAmountImg,
                           attribute: .width,
                           relatedBy: .lessThanOrEqual,
                           toItem: totalAmountView,
                           attribute: .width,
                           multiplier: 0.2,
                           constant: 0)
        imgWidth.identifier = "imgWidth"
        imgWidth.isActive = true
    



    //-----------------------------------------------------------------
    // MARK: - Actions
    //-----------------------------------------------------------------

    @IBAction func pageChange(_ sender: UIPageControl) 
        let x = CGFloat(sender.currentPage) * scrollView.frame.width
        scrollView.contentOffset = CGPoint(x: x, y: 0)
        pageController.currentPageIndicatorTintColor = UIColor.white
    




extension NSLayoutConstraint 


    override open var description: String 
        let id = identifier ?? ""
        return "id: \(id), constant: \(constant)" //you may print whatever you want here
    

日志

2018-01-12 16:27:27.934408+0530 Cafe Point[13577:258401] [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. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "id: , constant: 343.0",
    "id: , constant: 0.0",
    "id: , constant: 0.0",
    "id: , constant: 16.0",
    "id: , constant: 0.0",
    "id: , constant: 0.0",
    "id: , constant: 0.0",
    "id: imgLeft, constant: 4.0",
    "id: imgRight, constant: 16.0",
    "id: imgWidth, constant: 0.0"
)

Will attempt to recover by breaking constraint 
id: imgLeft, constant: 4.0

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.

【问题讨论】:

【参考方案1】:

试着改成这样:

    let imgRight = NSLayoutConstraint(item: totalAmountImg,
                       attribute: .right,
                       relatedBy: .equal,
                       toItem: totalAmountView,
                       attribute: .right,
                       multiplier: 1.0,
                       constant: -16)
    imgRight.identifier = "imgRight"
    imgRight.isActive = true

(注意将 16 更改为 -16)

在将情节提要中的约束与以编程方式创建的约束进行比较时,您必须小心,因为顺序很重要。

【讨论】:

【参考方案2】:

如警告所述:

将尝试通过打破约束来恢复 id: imgLeft, 常量: 4.0

您正在为图像视图提供左右约束。但也分配宽度。它会混淆 Image View,因为左右约束足以满足 Image View 的 Width 要求。

因此您可以使用两种组合:左/宽或右/宽。

您也可以使用其他组合,但为此,我们必须深入研究Priority 的约束。

【讨论】:

您可以在不使用优先级的情况下设置左、右和宽度约束,以用于更改视图宽度导致缩小另一个固定在左侧或右侧的视图的情况。在这种情况下,它只是一个 16 应该是 -16 并且一切正常。 哦..没想到那个场景! 当调试约束是错误的方式时,这是我学会的第一件事。我开始使用重叠视图的次数,因为我将间隙设置为 20 左右,但约束是错误的方式。【参考方案3】:

要正确理解布局,请记住,当您为视图提供前/左和后/右约束时,您不必给它一个宽度,就好像您将一件长袍固定在两侧一样,如果您愿意给它一个宽度然后给它一个centerX约束,同样也适用于顶部,底部然后不必给出高度,如果你想给出高度然后添加centerY约束,当然你可以给一个视图前导,尾随和同时限制宽度,但要确保它们适合在一起

【讨论】:

但是发送给前/左和尾/右约束,您可能还想给出宽度约束。例如,如果您有两个并排的视图,因此您对它们都设置了左/右约束,但您还对一个设置了宽度约束,这样当它的宽度发生变化时,其他视图的宽度也会发生变化,因为它们被固定在一起。 当你将它固定到像超级视图这样的刚性视图时,你不必指定宽度,所以根据它的邻居的大小,它会得到它的大小,当然当你在旁边放置两个时彼此必须给一个宽度,以便另一个可以在运行时根据屏幕高度或宽度等得到一个宽度,等等,我的意思同样适用于顶部、底部和高度 是的,说得好,但在这种情况下,问题是关于并排的两个视图。左侧的总计视图和右侧的刻度视图。无论如何,你说的都是正确的,但这里的问题只是 16 而不是 -16。 我知道改变为 totalAmountImg right+16 = totalAmountView right ,所以当你开始一个以 totalAmountImg 作为第一项的约束时,它应该是 totalAmountImg right = totalAmountView right -16 只是改变方程结构

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

无法同时满足约束 - Swift

无法同时满足约束 - LayoutConstraints

iOS:无法同时满足约束

无法同时满足约束。虽然没有定义重复/不需要的约束

关闭:“无法同时满足约束”[重复]

无法同时满足 UITextField 上的约束