为什么嵌入的 UIStackView 按比例填充间距和布局边距会导致约束错误以及如何修复?

Why do embedded UIStackView's, filled Proportionally, with spacing and Layout Margins causes constraint errors and how to fix?

这个问题来自于很棒的问答:

我遇到了类似的问题,但在滚动视图中嵌入了堆栈视图。我已经修改了上述问题的解释代码。在我的工作代码中,我有一个加载到容器视图中的父VC,一个具有嵌入式滚动视图和堆栈视图的子VC(外部堆栈视图是垂直的,然后它的每个子视图都是一堆水平堆栈视图)。有固定宽度标签、图标和扩展标签等一系列选项。

问题是我得到了 UISV 间距约束错误或扩展标签的尾随错误。我从上面的问题中了解到,这与自动布局引擎计算比例宽度、间距等的顺序有关,但不知道如何解决。欢迎大家提出意见。我附上了我正在使用的代码:

class ParentVC: UIViewController {
    
    override func viewDidLoad() {
        
        let vcContainer = UIView()
        view.addSubview(vcContainer)
        vcContainer.backgroundColor = .systemYellow
        vcContainer.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            vcContainer.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
            vcContainer.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -150),
            vcContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50),
            vcContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50),
        ])
        
        let vc = ChildVC()
        addChild(vc)
        vc.didMove(toParent: self)
        vcContainer.addSubview(vc.view)
        vc.view.frame = vcContainer.bounds
        vc.view.heightAnchor.constraint(equalTo: vcContainer.heightAnchor).isActive = true
    }
    
}

class ChildVC: UIViewController {

    let outerStackView: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.spacing = 8
        return v
    }()

    let scrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.translatesAutoresizingMaskIntoConstraints = false
        return sv
    }()


    override func viewDidLoad() {
        super.viewDidLoad()

        for _ in 1...7 {
            let lbl = UILabel()
            lbl.font = UIFont.systemFont(ofSize: 12.0, weight: .light)
            lbl.numberOfLines = 0
            lbl.textAlignment = .center
            outerStackView.addArrangedSubview(lbl)
            let sv = UIStackView()
            sv.translatesAutoresizingMaskIntoConstraints = false
            sv.axis = .horizontal
            sv.distribution = .fillProportionally
            sv.spacing = 10
            outerStackView.addArrangedSubview(sv)
        }

        view.addSubview(scrollView)
        scrollView.addSubview(outerStackView)

        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.widthAnchor.constraint(equalTo: view.widthAnchor),
            scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            scrollView.heightAnchor.constraint(equalTo: view.heightAnchor),
            
            outerStackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
            outerStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
            outerStackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
            outerStackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
            outerStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
        ])

        // StackView 1
        if let lbl = outerStackView.arrangedSubviews[0] as? UILabel,
            let sv = outerStackView.arrangedSubviews[1] as? UIStackView {

            let v = ExpandingLabel()
            sv.addArrangedSubview(v)

            lbl.text = "SV1: One view \n no layoutMargins"
        }

        // StackView 2
        if let lbl = outerStackView.arrangedSubviews[2] as? UILabel,
            let sv = outerStackView.arrangedSubviews[3] as? UIStackView {


            let v = FixedLabel()
            sv.addArrangedSubview(v)


            let v2 = ExpandingLabel()
            sv.addArrangedSubview(v2)

            lbl.text = "SV2: Two views \n no layoutMargins"
        }

        // comment out this block to see the auto-layout error goes away
        // StackView 3
        if let lbl = outerStackView.arrangedSubviews[4] as? UILabel,
            let sv = outerStackView.arrangedSubviews[5] as? UIStackView {


            let v = ExpandingLabel()
            sv.addArrangedSubview(v)

            sv.isLayoutMarginsRelativeArrangement = true
            sv.layoutMargins = .init(top: 0, left: 10, bottom: 0, right: 11)

            lbl.text = "SV3: One view\nlayoutMargins left: \(sv.layoutMargins.left), right: \(sv.layoutMargins.right)"
        }

        // StackView 4
        if let lbl = outerStackView.arrangedSubviews[6] as? UILabel,
            let sv = outerStackView.arrangedSubviews[7] as? UIStackView {

            let v = FixedLabel()
            sv.addArrangedSubview(v)

            let v2 = ExpandingLabel()
            sv.addArrangedSubview(v2)

            sv.isLayoutMarginsRelativeArrangement = true
            sv.layoutMargins = .init(top: 0, left: 12, bottom: 0, right: 13)
    
            lbl.text = "SV4: Two views\nlayoutMargins\n left:  \(sv.layoutMargins.left), right: \(sv.layoutMargins.right)"
        }

        // StackView 5
        if let lbl = outerStackView.arrangedSubviews[8] as? UILabel,
            let sv = outerStackView.arrangedSubviews[9] as? UIStackView {

            let v = FixedLabel()
            sv.addArrangedSubview(v)

            let v2 = ExpandingLabel()
            sv.addArrangedSubview(v2)

            sv.isLayoutMarginsRelativeArrangement = true
            sv.layoutMargins = .init(top: 0, left: 101, bottom: 0, right: 0)

            lbl.text = "SV5: Two views \nlayoutMargins left:  \(sv.layoutMargins.left), right: \(sv.layoutMargins.right)"
        }

        // StackView 6
        if let lbl = outerStackView.arrangedSubviews[10] as? UILabel,
            let sv = outerStackView.arrangedSubviews[11] as? UIStackView {

            let v = IconView()
            sv.addArrangedSubview(v)

            let v2 = ExpandingLabel()
            v2.numberOfLines = 0
            sv.addArrangedSubview(v2)

            sv.isLayoutMarginsRelativeArrangement = true
            sv.layoutMargins = .init(top: 0, left: 14, bottom: 0, right: 15)

            lbl.text = "SV6: Two views\nlayoutMargins left:  \(sv.layoutMargins.left), right: \(sv.layoutMargins.right)"
        }
        
        
        // StackView 7
        if let lbl = outerStackView.arrangedSubviews[12] as? UILabel,
            let sv = outerStackView.arrangedSubviews[13] as? UIStackView {


            let v = ExpandingLabel()
            sv.addArrangedSubview(v)

            sv.isLayoutMarginsRelativeArrangement = true
            sv.layoutMargins = .init(top: 0, left: 16, bottom: 0, right: 17)

            let v2 = ExpandingLabel()
            sv.addArrangedSubview(v2)

            lbl.text = "SV7: One view\nlayoutMargins left:  \(sv.layoutMargins.left), right: \(sv.layoutMargins.right)"
        }
    }

}


class IconView: UIImageView {
     init() {
        super.init(frame: .zero)
    
        self.backgroundColor = UIColor.systemRed
        self.tintColor = .white

        image = UIImage(systemName: "square.and.arrow.up")?.applyingSymbolConfiguration(UIImage.SymbolConfiguration(textStyle: .body))
        contentMode = .center
        
        translatesAutoresizingMaskIntoConstraints = false
        adjustsImageSizeForAccessibilityContentSizeCategory = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


class FixedLabel : UILabel {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        text = "fxd"
        backgroundColor = .systemRed
        
        translatesAutoresizingMaskIntoConstraints = false
        setContentCompressionResistancePriority(.required, for: .horizontal)
        setContentHuggingPriority(.required, for: .horizontal)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


class ExpandingLabel: UILabel {
  
    override init(frame: CGRect) {
        super.init(frame: frame)
        text = "expanding label"
        backgroundColor = .systemGreen
        numberOfLines = 3
        font = UIFont.preferredFont(forTextStyle: .body)
        adjustsFontForContentSizeCategory = true

        translatesAutoresizingMaskIntoConstraints = false
        setContentHuggingPriority(.defaultLow, for: .horizontal)
        setContentCompressionResistancePriority(.defaultHigh, for: .vertical)
        setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

以上生成如下所示的预期结果:

日志错误是:

2021-03-16 10:01:22.815997+1100 stackviewsWithProportionalFill[8528:4745644] Sherlock initialised 2021-03-16 10:01:23.051125+1100 stackviewsWithProportionalFill[8528:4745644] [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:0x600003317e80 'UISV-canvas-connection' UIStackView:0x7feb0270f930.leading == stackviewsWithProportionalFill.FixedLabel:0x7feb02715f80.leading   (active)>",
    "<NSLayoutConstraint:0x600003317930 'UISV-canvas-connection' H:[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0270b710]-(0)-| (active, names: '|':UIStackView:0x7feb0270f930 )>",
    "<NSLayoutConstraint:0x6000033172a0 'UISV-fill-proportionally' stackviewsWithProportionalFill.ExpandingLabel:0x7feb0270b710.width == UIStackView:0x7feb0270f930.width   (active)>",
    "<NSLayoutConstraint:0x6000033178e0 'UISV-spacing' H:[stackviewsWithProportionalFill.FixedLabel:0x7feb02715f80]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0270b710] (active)>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x6000033178e0 'UISV-spacing' H:[stackviewsWithProportionalFill.FixedLabel:0x7feb02715f80]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0270b710] (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. 2021-03-16 10:01:23.057974+1100 stackviewsWithProportionalFill[8528:4745644] [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:0x60000332cb40 UIScrollView:0x7feb0381ea00.width == UIView:0x7feb0270aeb0.width   (active)>",
    "<NSLayoutConstraint:0x60000332d270 UIStackView:0x7feb02709160.width == UIScrollView:0x7feb0381ea00.width  (active)>",
    "<NSLayoutConstraint:0x600003370fa0 'UISV-alignment' UILabel:0x7feb0270b2a0.leading == UIStackView:0x7feb02711930.leading   (active)>",
    "<NSLayoutConstraint:0x6000033713b0 'UISV-alignment' UILabel:0x7feb0270b2a0.trailing == UIStackView:0x7feb02711930.trailing (active)>",
    "<NSLayoutConstraint:0x600003310eb0 'UISV-canvas-connection' UILayoutGuide:0x6000029208c0'UIViewLayoutMarginsGuide'.leading == stackviewsWithProportionalFill.FixedLabel:0x7feb02717140.leading   (active)>",
    "<NSLayoutConstraint:0x6000033123f0 'UISV-canvas-connection' UILayoutGuide:0x6000029208c0'UIViewLayoutMarginsGuide'.trailing == stackviewsWithProportionalFill.ExpandingLabel:0x7feb02717530.trailing  (active)>",
    "<NSLayoutConstraint:0x600003370c80 'UISV-canvas-connection' UIStackView:0x7feb02709160.leading == UILabel:0x7feb0270b2a0.leading   (active)>",
    "<NSLayoutConstraint:0x600003370cd0 'UISV-canvas-connection' H:[UILabel:0x7feb0270b2a0]-(0)-|   (active, names: '|':UIStackView:0x7feb02709160 )>",
    "<NSLayoutConstraint:0x600003312530 'UISV-spacing' H:[stackviewsWithProportionalFill.FixedLabel:0x7feb02717140]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb02717530] (active)>",
    "<NSLayoutConstraint:0x600003371540 'UIView-Encapsulated-Layout-Width' UIView:0x7feb0270aeb0.width == 0   (active)>",
    "<NSLayoutConstraint:0x600003312300 'UIView-leftMargin-guide-constraint' H:|-(101)-[UILayoutGuide:0x6000029208c0'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':UIStackView:0x7feb02711930 )>",
    "<NSLayoutConstraint:0x6000033123a0 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x6000029208c0'UIViewLayoutMarginsGuide']-(0)-|(LTR)  (active, names: '|':UIStackView:0x7feb02711930 )>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x600003312530 'UISV-spacing' H:[stackviewsWithProportionalFill.FixedLabel:0x7feb02717140]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb02717530] (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. 2021-03-16 10:01:23.065566+1100 stackviewsWithProportionalFill[8528:4745644] [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:0x60000332cb40 UIScrollView:0x7feb0381ea00.width == UIView:0x7feb0270aeb0.width   (active)>",
    "<NSLayoutConstraint:0x60000332d270 UIStackView:0x7feb02709160.width == UIScrollView:0x7feb0381ea00.width  (active)>",
    "<NSLayoutConstraint:0x6000033710e0 'UISV-alignment' UILabel:0x7feb0270b2a0.leading == UIStackView:0x7feb02712730.leading   (active)>",
    "<NSLayoutConstraint:0x6000033714f0 'UISV-alignment' UILabel:0x7feb0270b2a0.trailing == UIStackView:0x7feb02712730.trailing (active)>",
    "<NSLayoutConstraint:0x6000033138e0 'UISV-canvas-connection' UILayoutGuide:0x600002920a80'UIViewLayoutMarginsGuide'.leading == stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260e660.leading   (active)>",
    "<NSLayoutConstraint:0x600003313930 'UISV-canvas-connection' UILayoutGuide:0x600002920a80'UIViewLayoutMarginsGuide'.trailing == stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260ecd0.trailing  (active)>",
    "<NSLayoutConstraint:0x600003370c80 'UISV-canvas-connection' UIStackView:0x7feb02709160.leading == UILabel:0x7feb0270b2a0.leading   (active)>",
    "<NSLayoutConstraint:0x600003370cd0 'UISV-canvas-connection' H:[UILabel:0x7feb0270b2a0]-(0)-|   (active, names: '|':UIStackView:0x7feb02709160 )>",
    "<NSLayoutConstraint:0x600003370050 'UISV-spacing' H:[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260e660]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260ecd0] (active)>",
    "<NSLayoutConstraint:0x600003371540 'UIView-Encapsulated-Layout-Width' UIView:0x7feb0270aeb0.width == 0   (active)>",
    "<NSLayoutConstraint:0x6000033137f0 'UIView-leftMargin-guide-constraint' H:|-(16)-[UILayoutGuide:0x600002920a80'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':UIStackView:0x7feb02712730 )>",
    "<NSLayoutConstraint:0x600003313890 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600002920a80'UIViewLayoutMarginsGuide']-(17)-|(LTR) (active, names: '|':UIStackView:0x7feb02712730 )>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x600003370050 'UISV-spacing' H:[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260e660]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260ecd0] (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. 2021-03-16 10:01:23.066504+1100 stackviewsWithProportionalFill[8528:4745644] [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:0x60000332cb40 UIScrollView:0x7feb0381ea00.width == UIView:0x7feb0270aeb0.width   (active)>",
    "<NSLayoutConstraint:0x60000332d270 UIStackView:0x7feb02709160.width == UIScrollView:0x7feb0381ea00.width  (active)>",
    "<NSLayoutConstraint:0x600003371040 'UISV-alignment' UILabel:0x7feb0270b2a0.leading == UIStackView:0x7feb02712130.leading   (active)>",
    "<NSLayoutConstraint:0x600003371450 'UISV-alignment' UILabel:0x7feb0270b2a0.trailing == UIStackView:0x7feb02712130.trailing (active)>",
    "<NSLayoutConstraint:0x600003312e90 'UISV-canvas-connection' UILayoutGuide:0x600002920b60'UIViewLayoutMarginsGuide'.leading == stackviewsWithProportionalFill.IconView:0x7feb027179a0.leading   (active)>",
    "<NSLayoutConstraint:0x600003312ee0 'UISV-canvas-connection' UILayoutGuide:0x600002920b60'UIViewLayoutMarginsGuide'.trailing == stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260e1f0.trailing  (active)>",
    "<NSLayoutConstraint:0x600003370c80 'UISV-canvas-connection' UIStackView:0x7feb02709160.leading == UILabel:0x7feb0270b2a0.leading   (active)>",
    "<NSLayoutConstraint:0x600003370cd0 'UISV-canvas-connection' H:[UILabel:0x7feb0270b2a0]-(0)-|   (active, names: '|':UIStackView:0x7feb02709160 )>",
    "<NSLayoutConstraint:0x600003313020 'UISV-spacing' H:[stackviewsWithProportionalFill.IconView:0x7feb027179a0]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260e1f0] (active)>",
    "<NSLayoutConstraint:0x600003371540 'UIView-Encapsulated-Layout-Width' UIView:0x7feb0270aeb0.width == 0   (active)>",
    "<NSLayoutConstraint:0x600003312da0 'UIView-leftMargin-guide-constraint' H:|-(14)-[UILayoutGuide:0x600002920b60'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':UIStackView:0x7feb02712130 )>",
    "<NSLayoutConstraint:0x600003312e40 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600002920b60'UIViewLayoutMarginsGuide']-(15)-|(LTR) (active, names: '|':UIStackView:0x7feb02712130 )>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x600003313020 'UISV-spacing' H:[stackviewsWithProportionalFill.IconView:0x7feb027179a0]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb0260e1f0] (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. 2021-03-16 10:01:23.067723+1100 stackviewsWithProportionalFill[8528:4745644] [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:0x60000332cb40 UIScrollView:0x7feb0381ea00.width == UIView:0x7feb0270aeb0.width   (active)>",
    "<NSLayoutConstraint:0x60000332d270 UIStackView:0x7feb02709160.width == UIScrollView:0x7feb0381ea00.width  (active)>",
    "<NSLayoutConstraint:0x600003370f00 'UISV-alignment' UILabel:0x7feb0270b2a0.leading == UIStackView:0x7feb02710b30.leading   (active)>",
    "<NSLayoutConstraint:0x600003371310 'UISV-alignment' UILabel:0x7feb0270b2a0.trailing == UIStackView:0x7feb02710b30.trailing (active)>",
    "<NSLayoutConstraint:0x6000033118b0 'UISV-canvas-connection' UILayoutGuide:0x600002920380'UIViewLayoutMarginsGuide'.leading == stackviewsWithProportionalFill.FixedLabel:0x7feb02716a60.leading   (active)>",
    "<NSLayoutConstraint:0x600003311900 'UISV-canvas-connection' UILayoutGuide:0x600002920380'UIViewLayoutMarginsGuide'.trailing == stackviewsWithProportionalFill.ExpandingLabel:0x7feb02716cd0.trailing  (active)>",
    "<NSLayoutConstraint:0x600003370c80 'UISV-canvas-connection' UIStackView:0x7feb02709160.leading == UILabel:0x7feb0270b2a0.leading   (active)>",
    "<NSLayoutConstraint:0x600003370cd0 'UISV-canvas-connection' H:[UILabel:0x7feb0270b2a0]-(0)-|   (active, names: '|':UIStackView:0x7feb02709160 )>",
    "<NSLayoutConstraint:0x600003311a40 'UISV-spacing' H:[stackviewsWithProportionalFill.FixedLabel:0x7feb02716a60]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb02716cd0] (active)>",
    "<NSLayoutConstraint:0x600003371540 'UIView-Encapsulated-Layout-Width' UIView:0x7feb0270aeb0.width == 0   (active)>",
    "<NSLayoutConstraint:0x6000033117c0 'UIView-leftMargin-guide-constraint' H:|-(12)-[UILayoutGuide:0x600002920380'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':UIStackView:0x7feb02710b30 )>",
    "<NSLayoutConstraint:0x600003311860 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600002920380'UIViewLayoutMarginsGuide']-(13)-|(LTR) (active, names: '|':UIStackView:0x7feb02710b30 )>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x600003311a40 'UISV-spacing' H:[stackviewsWithProportionalFill.FixedLabel:0x7feb02716a60]-(10)-[stackviewsWithProportionalFill.ExpandingLabel:0x7feb02716cd0] (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. 2021-03-16 10:01:23.068649+1100 stackviewsWithProportionalFill[8528:4745644] [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:0x60000332cb40 UIScrollView:0x7feb0381ea00.width == UIView:0x7feb0270aeb0.width   (active)>",
    "<NSLayoutConstraint:0x60000332d270 UIStackView:0x7feb02709160.width == UIScrollView:0x7feb0381ea00.width  (active)>",
    "<NSLayoutConstraint:0x600003370e60 'UISV-alignment' UILabel:0x7feb0270b2a0.leading == UIStackView:0x7feb02710130.leading   (active)>",
    "<NSLayoutConstraint:0x600003371270 'UISV-alignment' UILabel:0x7feb0270b2a0.trailing == UIStackView:0x7feb02710130.trailing (active)>",
    "<NSLayoutConstraint:0x600003316df0 'UISV-canvas-connection' UILayoutGuide:0x600002939880'UIViewLayoutMarginsGuide'.leading == stackviewsWithProportionalFill.ExpandingLabel:0x7feb027167f0.leading   (active)>",
    "<NSLayoutConstraint:0x600003316da0 'UISV-canvas-connection' UILayoutGuide:0x600002939880'UIViewLayoutMarginsGuide'.trailing == stackviewsWithProportionalFill.ExpandingLabel:0x7feb027167f0.trailing  (active)>",
    "<NSLayoutConstraint:0x600003370c80 'UISV-canvas-connection' UIStackView:0x7feb02709160.leading == UILabel:0x7feb0270b2a0.leading   (active)>",
    "<NSLayoutConstraint:0x600003370cd0 'UISV-canvas-connection' H:[UILabel:0x7feb0270b2a0]-(0)-|   (active, names: '|':UIStackView:0x7feb02709160 )>",
    "<NSLayoutConstraint:0x600003371540 'UIView-Encapsulated-Layout-Width' UIView:0x7feb0270aeb0.width == 0   (active)>",
    "<NSLayoutConstraint:0x600003316ee0 'UIView-leftMargin-guide-constraint' H:|-(10)-[UILayoutGuide:0x600002939880'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':UIStackView:0x7feb02710130 )>",
    "<NSLayoutConstraint:0x600003316e40 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600002939880'UIViewLayoutMarginsGuide']-(11)-|(LTR) (active, names: '|':UIStackView:0x7feb02710130 )>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x600003316da0 'UISV-canvas-connection' UILayoutGuide:0x600002939880'UIViewLayoutMarginsGuide'.trailing == stackviewsWithProportionalFill.ExpandingLabel:0x7feb027167f0.trailing  (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. 2021-03-16 10:01:24.091972+1100 stackviewsWithProportionalFill[8528:4745811] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed

你无意中提出了我告诉人们*忘记你听说过 UIStackView 的 属性 分布 属性 的(许多)原​​因之一...

对于水平堆栈视图,您有:

sv.distribution = .fillProportionally

所以你刚刚告诉auto-layout:“将排列的子视图的宽度按比例拉伸到彼此!”

然后添加一个标签作为已排列的子视图,并在标签上设置 属性:

setContentHuggingPriority(.required, for: .horizontal)

所以你刚刚告诉 auto-layout:“不要拉伸这个标签的宽度!”

auto-layout 很难同时拉伸不拉伸 视图:)

除非你确切地知道你为什么想要 .fillProportionally(在这种情况下,那是 而不是 你想要的) ,不要使用它。对于您的布局,您需要默认的 .fill.

所以,如果我们暂时忘记您正在加载 ChildVC 作为 child VC (grin)并将 ChildVC 设置为“根”视图控制器,并保留 sv.distribution = .fillProportionally,你会得到布局错误。

如果将其更改为 sv.distribution = .fill,您 将不会 出现布局错误。

但是,回到将 VC 用作 child ... 即使使用 .fill 你仍然会遇到布局错误.所以...

ParentVC 中的“加载 child”代码更改为:

class ParentVC: UIViewController {
    
    override func viewDidLoad() {
        
        let vcContainer = UIView()
        view.addSubview(vcContainer)
        vcContainer.backgroundColor = .systemYellow
        vcContainer.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            vcContainer.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
            vcContainer.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -150),
            vcContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50),
            vcContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50),
        ])
        
        let vc = ChildVC()
        addChild(vc)
        vcContainer.addSubview(vc.view)
        
        vc.view.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            vc.view.topAnchor.constraint(equalTo: vcContainer.topAnchor),
            vc.view.leadingAnchor.constraint(equalTo: vcContainer.leadingAnchor),
            vc.view.trailingAnchor.constraint(equalTo: vcContainer.trailingAnchor),
            vc.view.bottomAnchor.constraint(equalTo: vcContainer.bottomAnchor),
        ])
        
        vc.didMove(toParent: self)
    }
    
}

这种方法与 sv.distribution = .fill 相结合,消除了错误。