Reputation: 813
I have a simple ViewController
with a custom subview called MyView
:
import UIKit
class ViewController: UIViewController {
let myView = MyView()
override func viewDidLoad() {
super.viewDidLoad()
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
myView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
}
}
class MyView: UIView {
let stackView: UIStackView
let label = UILabel()
let label2 = UILabel()
init() {
stackView = UIStackView(arrangedSubviews: [label, label2])
super.init(frame: .zero)
stackView.axis = .vertical
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Label 1"
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "Label 2"
stackView.spacing = 8.0
addSubview(stackView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func updateConstraints() {
super.updateConstraints()
stackView.fillSuperview()
}
}
When I run this, I get the following breaking constraints in the console:
2018-03-23 16:11:58.960493+0100 ViewWithStackView[75612:10756278] [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:0x608000280f00 'UISV-canvas-connection' UIStackView:0x7f8438e07510.top == UILabel:0x7f8438d06740'Label 1'.top (active)>",
"<NSLayoutConstraint:0x608000280fa0 'UISV-canvas-connection' V:[UILabel:0x7f8438e07790'Label 2']-(0)-| (active, names: '|':UIStackView:0x7f8438e07510 )>",
"<NSLayoutConstraint:0x608000280ff0 'UISV-spacing' V:[UILabel:0x7f8438d06740'Label 1']-(8)-[UILabel:0x7f8438e07790'Label 2'] (active)>",
"<NSLayoutConstraint:0x608000280550 'UIView-Encapsulated-Layout-Height' UIStackView:0x7f8438e07510.height == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x608000280ff0 'UISV-spacing' V:[UILabel:0x7f8438d06740'Label 1']-(8)-[UILabel:0x7f8438e07790'Label 2'] (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-03-23 16:11:58.961737+0100 ViewWithStackView[75612:10756278]
[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)
(
"<NSAutoresizingMaskLayoutConstraint:0x6080002812c0 h=--& v=--& UIStackView:0x7f8438e07510.height == 0 (active)>",
"<NSLayoutConstraint:0x608000280f00 'UISV-canvas-connection' UIStackView:0x7f8438e07510.top == UILabel:0x7f8438d06740'Label 1'.top (active)>",
"<NSLayoutConstraint:0x608000280fa0 'UISV-canvas-connection' V:[UILabel:0x7f8438e07790'Label 2']-(0)-| (active, names: '|':UIStackView:0x7f8438e07510 )>",
"<NSLayoutConstraint:0x608000280ff0 'UISV-spacing' V:[UILabel:0x7f8438d06740'Label 1']-(8)-[UILabel:0x7f8438e07790'Label 2'] (active)>"
)
Will attempt to recover by breaking constraint
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.
Now if I move the following line stackView.spacing = 8.0
to the updateConstraints
method, the constraints won't break. So the following code works fine without warning / error in the console:
import UIKit
class ViewController: UIViewController {
let myView = MyView()
override func viewDidLoad() {
super.viewDidLoad()
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
myView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
}
}
class MyView: UIView {
let stackView: UIStackView
let label = UILabel()
let label2 = UILabel()
init() {
stackView = UIStackView(arrangedSubviews: [label, label2])
super.init(frame: .zero)
stackView.axis = .vertical
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Label 1"
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "Label 2"
addSubview(stackView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func updateConstraints() {
super.updateConstraints()
stackView.fillSuperview()
stackView.spacing = 8.0
}
}
Why does moving stackView.spacing = 8.0
to updateConstraints
solve this issue / remove the warnings / errors?
Thank you for an explanation :)
Upvotes: 1
Views: 2917
Reputation: 13276
It looks like this is the constraint you don't want
"<NSLayoutConstraint:0x608000280550 'UIView-Encapsulated-Layout-Height' UIStackView:0x7f8438e07510.height == 0 (active)>"
The first thing I'd try is
stackView.translatesAutoresizingMaskIntoConstraints = false
Also, I don't know what stackView.fillSuperview()
is doing but you'd probably be better off adding constraints to it so fills the view.
Upvotes: 4
Reputation: 100503
In the first case the stackView has a zero height because you haven't set a frame for it ( in init
before fillSuperview()
), so setting a spacing of 8 between the 2 labels will cause a conflict , but in second the frame is zero and spacing is zero and the 2 labels will have a zero height according to (intrinsic content size) so, in this case no conflict will happen , then you set spacing in updateConstraints
but at that moment stackView has a frame equal to it's superView according to this line fillSuperview()
so that goes smoothly also
Upvotes: 0