布局指南与自动布局约束冲突
Layout guide has conflicts with auto layout constraints
我在一本书中输入了一个示例,用于 iOS 编程,但该示例不起作用。示例的结果应该如下图所示:
示例代码如下:
import UIKit
class ViewsController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
layoutViews()
}
func layoutViews () {
let v1 = UIView(frame: CGRect(0, 0, 200, 30))
let v2 = UIView(frame: CGRect(0, 50, 200, 30))
let v3 = UIView(frame: CGRect(0, 80, 200, 30))
let v4 = UIView(frame: CGRect(0, 150, 200, 30))
let views = [v1, v2, v3, v4]
let colors = [UIColor.red, UIColor.blue, UIColor.yellow, UIColor.green]
var guides = [UILayoutGuide]()
for (v, c) in zip(views, colors) {
v.backgroundColor = c
}
for v in views {
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)
}
// one fewer guides than views
for _ in views.dropLast() {
let g = UILayoutGuide()
self.view.addLayoutGuide(g)
guides.append(g)
}
// guides leading and width are arbitrary
let anc = self.view.leadingAnchor
for g in guides {
g.leadingAnchor.constraint(equalTo: anc).isActive = true
g.widthAnchor.constraint(equalToConstant: 10).isActive = true
}
// guides top to previous view
for (v,g) in zip(views.dropLast(), guides) {
v.bottomAnchor.constraint(equalTo: g.topAnchor).isActive = true
}
// guides bottom to next view
for (v,g) in zip(views.dropFirst(), guides) {
v.topAnchor.constraint(equalTo: g.bottomAnchor).isActive = true
}
let h = guides[0].heightAnchor
for g in guides.dropFirst() {
g.heightAnchor.constraint(equalTo: h).isActive = true
}
}
}
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
extension CGRect {
var center : CGPoint {
return CGPoint(self.midX, self.midY)
}
}
extension CGRect {
func centeredRectOfSize(_ sz:CGSize) -> CGRect {
let c = self.center
let x = c.x - sz.width/2.0
let y = c.y - sz.height/2.0
return CGRect(x, y, sz.width, sz.height)
}
}
extension CGSize {
init(_ width:CGFloat, _ height:CGFloat) {
self.init(width:width, height:height)
}
}
extension CGPoint {
init(_ x:CGFloat, _ y:CGFloat) {
self.init(x:x, y:y)
}
}
extension CGVector {
init (_ dx:CGFloat, _ dy:CGFloat) {
self.init(dx:dx, dy:dy)
}
}
示例中,一开始并没有
这样一行代码
v.translatesAutoresizingMaskIntoConstraints = false
程序运行结果如下图:
并且在控制台中,有以下警告消息:
2021-06-10 10:47:03.267054+1000 Chapter1Views[19879:4731640] [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:0x600003b745f0 h=--& v=--& UIView:0x12ad170a0.minY == 0 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74550 h=--& v=--& UIView:0x12ad170a0.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74000 h=--& v=--& UIView:0x12ad16120.minY == 50 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b770c0 h=--& v=--& UIView:0x12ad16120.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b771b0 h=--& v=--& UIView:0x12ad16290.minY == 80 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSLayoutConstraint:0x600003b51e00 UIView:0x12ad170a0.bottom == UILayoutGuide:0x60000215d5e0''.top (active)>",
"<NSLayoutConstraint:0x600003b51ea0 UIView:0x12ad16120.bottom == UILayoutGuide:0x60000215d6c0''.top (active)>",
"<NSLayoutConstraint:0x600003b51f40 V:[UILayoutGuide:0x60000215d5e0'']-(0)-[UIView:0x12ad16120] (active)>",
"<NSLayoutConstraint:0x600003b51f90 V:[UILayoutGuide:0x60000215d6c0'']-(0)-[UIView:0x12ad16290] (active)>",
"<NSLayoutConstraint:0x600003b51fe0 UILayoutGuide:0x60000215d6c0''.height == UILayoutGuide:0x60000215d5e0''.height (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003b51f90 V:[UILayoutGuide:0x60000215d6c0'']-(0)-[UIView:0x12ad16290] (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-06-10 10:47:03.269574+1000 Chapter1Views[19879:4731640] [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:0x600003b745f0 h=--& v=--& UIView:0x12ad170a0.minY == 0 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74550 h=--& v=--& UIView:0x12ad170a0.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74000 h=--& v=--& UIView:0x12ad16120.minY == 50 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b771b0 h=--& v=--& UIView:0x12ad16290.minY == 80 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b77200 h=--& v=--& UIView:0x12ad16290.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b45b80 h=--& v=--& UIView:0x12ad16670.minY == 150 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSLayoutConstraint:0x600003b51e00 UIView:0x12ad170a0.bottom == UILayoutGuide:0x60000215d5e0''.top (active)>",
"<NSLayoutConstraint:0x600003b51ef0 UIView:0x12ad16290.bottom == UILayoutGuide:0x60000215e220''.top (active)>",
"<NSLayoutConstraint:0x600003b51f40 V:[UILayoutGuide:0x60000215d5e0'']-(0)-[UIView:0x12ad16120] (active)>",
"<NSLayoutConstraint:0x600003b51e50 V:[UILayoutGuide:0x60000215e220'']-(0)-[UIView:0x12ad16670] (active)>",
"<NSLayoutConstraint:0x600003b52030 UILayoutGuide:0x60000215e220''.height == UILayoutGuide:0x60000215d5e0''.height (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003b51e50 V:[UILayoutGuide:0x60000215e220'']-(0)-[UIView:0x12ad16670] (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.
这里好像有两种冲突。一个冲突是自动布局指南和视图的自动调整大小掩码之间的冲突,另一个是自动布局指南和视图的自动布局约束之间的冲突。
因此,为了解决第一个冲突,我添加了行代码:
v.translatesAutoresizingMaskIntoConstraints = false
然而,结果是模拟器屏幕上没有任何显示。
我不知道如何解决第二个冲突,即自动布局指南和视图的自动布局约束之间的冲突。
感谢您的帮助!
这是使用 UILayoutGuide
“间隔符”实现相等垂直间距的方法,缺少/更正代码:
func layoutViews () {
let v1 = UIView()
let v2 = UIView()
let v3 = UIView()
let v4 = UIView()
let views = [v1, v2, v3, v4]
let colors = [UIColor.red, UIColor.blue, UIColor.yellow, UIColor.green]
var guides = [UILayoutGuide]()
for (v, c) in zip(views, colors) {
v.backgroundColor = c
}
for v in views {
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)
}
// one fewer guides than views
for _ in views.dropLast() {
let g = UILayoutGuide()
self.view.addLayoutGuide(g)
guides.append(g)
}
// respect safe-area
let safeG = view.safeAreaLayoutGuide
// guides leading and width are arbitrary
let anc = safeG.leadingAnchor
for g in guides {
g.leadingAnchor.constraint(equalTo: anc).isActive = true
g.widthAnchor.constraint(equalToConstant: 10).isActive = true
}
// all 4 views constrain leading and trailing
for v in views {
v.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 20.0).isActive = true
v.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -20.0).isActive = true
}
// references to first and last views
guard let firstView = views.first,
let lastView = views.last
else {
fatalError("Incorrect setup!")
}
// first view, constrain to top
firstView.topAnchor.constraint(equalTo: safeG.topAnchor).isActive = true
// last view, constrain to bottom
lastView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor).isActive = true
// guides top to previous view
for (v,g) in zip(views.dropLast(), guides) {
g.topAnchor.constraint(equalTo: v.bottomAnchor).isActive = true
}
// guides bottom to next view
for (v,g) in zip(views.dropFirst(), guides) {
g.bottomAnchor.constraint(equalTo: v.topAnchor).isActive = true
}
// first view, constrain height to 30
views[0].heightAnchor.constraint(equalToConstant: 30.0).isActive = true
// remaining views heightAnchor equal to first view heightAnchor
for v in views.dropFirst() {
v.heightAnchor.constraint(equalTo: firstView.heightAnchor).isActive = true
}
let h = guides[0].heightAnchor
for g in guides.dropFirst() {
g.heightAnchor.constraint(equalTo: h).isActive = true
}
}
现在,这是做同样事情的一种方法,但使用 UIStackView
布局:
func layoutViews () {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .equalSpacing
let colors = [UIColor.red, UIColor.blue, UIColor.yellow, UIColor.green]
colors.forEach { c in
let v = UIView()
v.backgroundColor = c
v.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
stackView.addArrangedSubview(v)
}
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
// respect safe-area
let safeG = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: safeG.topAnchor),
stackView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 20.0),
stackView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -20.0),
stackView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),
])
}
如您所见...代码行少得多,要处理的对象和约束也少得多。
我在一本书中输入了一个示例,用于 iOS 编程,但该示例不起作用。示例的结果应该如下图所示:
示例代码如下:
import UIKit
class ViewsController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
layoutViews()
}
func layoutViews () {
let v1 = UIView(frame: CGRect(0, 0, 200, 30))
let v2 = UIView(frame: CGRect(0, 50, 200, 30))
let v3 = UIView(frame: CGRect(0, 80, 200, 30))
let v4 = UIView(frame: CGRect(0, 150, 200, 30))
let views = [v1, v2, v3, v4]
let colors = [UIColor.red, UIColor.blue, UIColor.yellow, UIColor.green]
var guides = [UILayoutGuide]()
for (v, c) in zip(views, colors) {
v.backgroundColor = c
}
for v in views {
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)
}
// one fewer guides than views
for _ in views.dropLast() {
let g = UILayoutGuide()
self.view.addLayoutGuide(g)
guides.append(g)
}
// guides leading and width are arbitrary
let anc = self.view.leadingAnchor
for g in guides {
g.leadingAnchor.constraint(equalTo: anc).isActive = true
g.widthAnchor.constraint(equalToConstant: 10).isActive = true
}
// guides top to previous view
for (v,g) in zip(views.dropLast(), guides) {
v.bottomAnchor.constraint(equalTo: g.topAnchor).isActive = true
}
// guides bottom to next view
for (v,g) in zip(views.dropFirst(), guides) {
v.topAnchor.constraint(equalTo: g.bottomAnchor).isActive = true
}
let h = guides[0].heightAnchor
for g in guides.dropFirst() {
g.heightAnchor.constraint(equalTo: h).isActive = true
}
}
}
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
extension CGRect {
var center : CGPoint {
return CGPoint(self.midX, self.midY)
}
}
extension CGRect {
func centeredRectOfSize(_ sz:CGSize) -> CGRect {
let c = self.center
let x = c.x - sz.width/2.0
let y = c.y - sz.height/2.0
return CGRect(x, y, sz.width, sz.height)
}
}
extension CGSize {
init(_ width:CGFloat, _ height:CGFloat) {
self.init(width:width, height:height)
}
}
extension CGPoint {
init(_ x:CGFloat, _ y:CGFloat) {
self.init(x:x, y:y)
}
}
extension CGVector {
init (_ dx:CGFloat, _ dy:CGFloat) {
self.init(dx:dx, dy:dy)
}
}
示例中,一开始并没有
这样一行代码v.translatesAutoresizingMaskIntoConstraints = false
程序运行结果如下图:
并且在控制台中,有以下警告消息:
2021-06-10 10:47:03.267054+1000 Chapter1Views[19879:4731640] [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:0x600003b745f0 h=--& v=--& UIView:0x12ad170a0.minY == 0 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74550 h=--& v=--& UIView:0x12ad170a0.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74000 h=--& v=--& UIView:0x12ad16120.minY == 50 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b770c0 h=--& v=--& UIView:0x12ad16120.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b771b0 h=--& v=--& UIView:0x12ad16290.minY == 80 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSLayoutConstraint:0x600003b51e00 UIView:0x12ad170a0.bottom == UILayoutGuide:0x60000215d5e0''.top (active)>",
"<NSLayoutConstraint:0x600003b51ea0 UIView:0x12ad16120.bottom == UILayoutGuide:0x60000215d6c0''.top (active)>",
"<NSLayoutConstraint:0x600003b51f40 V:[UILayoutGuide:0x60000215d5e0'']-(0)-[UIView:0x12ad16120] (active)>",
"<NSLayoutConstraint:0x600003b51f90 V:[UILayoutGuide:0x60000215d6c0'']-(0)-[UIView:0x12ad16290] (active)>",
"<NSLayoutConstraint:0x600003b51fe0 UILayoutGuide:0x60000215d6c0''.height == UILayoutGuide:0x60000215d5e0''.height (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003b51f90 V:[UILayoutGuide:0x60000215d6c0'']-(0)-[UIView:0x12ad16290] (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-06-10 10:47:03.269574+1000 Chapter1Views[19879:4731640] [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:0x600003b745f0 h=--& v=--& UIView:0x12ad170a0.minY == 0 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74550 h=--& v=--& UIView:0x12ad170a0.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b74000 h=--& v=--& UIView:0x12ad16120.minY == 50 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b771b0 h=--& v=--& UIView:0x12ad16290.minY == 80 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b77200 h=--& v=--& UIView:0x12ad16290.height == 30 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x600003b45b80 h=--& v=--& UIView:0x12ad16670.minY == 150 (active, names: '|':UIView:0x12ad16a00 )>",
"<NSLayoutConstraint:0x600003b51e00 UIView:0x12ad170a0.bottom == UILayoutGuide:0x60000215d5e0''.top (active)>",
"<NSLayoutConstraint:0x600003b51ef0 UIView:0x12ad16290.bottom == UILayoutGuide:0x60000215e220''.top (active)>",
"<NSLayoutConstraint:0x600003b51f40 V:[UILayoutGuide:0x60000215d5e0'']-(0)-[UIView:0x12ad16120] (active)>",
"<NSLayoutConstraint:0x600003b51e50 V:[UILayoutGuide:0x60000215e220'']-(0)-[UIView:0x12ad16670] (active)>",
"<NSLayoutConstraint:0x600003b52030 UILayoutGuide:0x60000215e220''.height == UILayoutGuide:0x60000215d5e0''.height (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003b51e50 V:[UILayoutGuide:0x60000215e220'']-(0)-[UIView:0x12ad16670] (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.
这里好像有两种冲突。一个冲突是自动布局指南和视图的自动调整大小掩码之间的冲突,另一个是自动布局指南和视图的自动布局约束之间的冲突。
因此,为了解决第一个冲突,我添加了行代码:
v.translatesAutoresizingMaskIntoConstraints = false
然而,结果是模拟器屏幕上没有任何显示。
我不知道如何解决第二个冲突,即自动布局指南和视图的自动布局约束之间的冲突。
感谢您的帮助!
这是使用 UILayoutGuide
“间隔符”实现相等垂直间距的方法,缺少/更正代码:
func layoutViews () {
let v1 = UIView()
let v2 = UIView()
let v3 = UIView()
let v4 = UIView()
let views = [v1, v2, v3, v4]
let colors = [UIColor.red, UIColor.blue, UIColor.yellow, UIColor.green]
var guides = [UILayoutGuide]()
for (v, c) in zip(views, colors) {
v.backgroundColor = c
}
for v in views {
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)
}
// one fewer guides than views
for _ in views.dropLast() {
let g = UILayoutGuide()
self.view.addLayoutGuide(g)
guides.append(g)
}
// respect safe-area
let safeG = view.safeAreaLayoutGuide
// guides leading and width are arbitrary
let anc = safeG.leadingAnchor
for g in guides {
g.leadingAnchor.constraint(equalTo: anc).isActive = true
g.widthAnchor.constraint(equalToConstant: 10).isActive = true
}
// all 4 views constrain leading and trailing
for v in views {
v.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 20.0).isActive = true
v.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -20.0).isActive = true
}
// references to first and last views
guard let firstView = views.first,
let lastView = views.last
else {
fatalError("Incorrect setup!")
}
// first view, constrain to top
firstView.topAnchor.constraint(equalTo: safeG.topAnchor).isActive = true
// last view, constrain to bottom
lastView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor).isActive = true
// guides top to previous view
for (v,g) in zip(views.dropLast(), guides) {
g.topAnchor.constraint(equalTo: v.bottomAnchor).isActive = true
}
// guides bottom to next view
for (v,g) in zip(views.dropFirst(), guides) {
g.bottomAnchor.constraint(equalTo: v.topAnchor).isActive = true
}
// first view, constrain height to 30
views[0].heightAnchor.constraint(equalToConstant: 30.0).isActive = true
// remaining views heightAnchor equal to first view heightAnchor
for v in views.dropFirst() {
v.heightAnchor.constraint(equalTo: firstView.heightAnchor).isActive = true
}
let h = guides[0].heightAnchor
for g in guides.dropFirst() {
g.heightAnchor.constraint(equalTo: h).isActive = true
}
}
现在,这是做同样事情的一种方法,但使用 UIStackView
布局:
func layoutViews () {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .equalSpacing
let colors = [UIColor.red, UIColor.blue, UIColor.yellow, UIColor.green]
colors.forEach { c in
let v = UIView()
v.backgroundColor = c
v.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
stackView.addArrangedSubview(v)
}
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
// respect safe-area
let safeG = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: safeG.topAnchor),
stackView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 20.0),
stackView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -20.0),
stackView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),
])
}
如您所见...代码行少得多,要处理的对象和约束也少得多。