以编程方式(没有情节提要),我尝试删除一组约束并在设备旋转时创建一组新约束。我用来删除约束的代码可以正确执行,但实际上并没有删除约束。添加新的(冲突的)约束集时,这会导致布局错误。
我正在使用没有故事板的Xcode 10.1和Swift 4.2。在我的MainViewController中,我正在根据viewDidLoad()
调用的函数创建并放置一个名为“ ticketsView”的UICollectionView。在addChild()
和addSubview()
之后,我调用了一个名为applyTicketsViewConstraints()
的函数,该函数确定设备的当前方向,然后(预期)删除所有现有约束并为它们应用适当的约束集当前的设备方向。
我重写viewWillTransition:toSize:withCoordinator()
,只要旋转设备,它就会从协调器闭包内部调用相同的applyTicketsViewConstraints()
函数。
在应用启动时,将根据初始设备方向正确应用约束。第一次将设备旋转90度时,显示也会成功更改,但是此后的任何旋转都会导致“ [LayoutConstraints]无法同时满足约束条件”错误消息。
我尝试遍历现有的ticketView约束并一次删除一个约束,并且尝试一次将其全部删除-但两种方法都无法真正去除约束。它们似乎都可以成功运行,但是约束完成后仍然存在。
func createTicketCollectionWindow() {
ticketsLayout = UICollectionViewFlowLayout()
ticketsVC = TicketCollectionController(collectionViewLayout: ticketsLayout)
ticketsVC?.collectionView?.backgroundColor = UIColor.darkGray
ticketsView = ticketsVC!.view
ticketsView.translatesAutoresizingMaskIntoConstraints = false
addChild(ticketsVC!)
self.view.addSubview(ticketsView)
applyTicketsViewConstraints()
}
func applyTicketsViewConstraints() {
let safe = self.view.safeAreaLayoutGuide
let deviceSize = UIScreen.main.bounds.size
for individualConstraint in ticketsView.constraints {
print("TicketViewConstraints: Removing Constraint: \(individualConstraint)" )
// ticketsView.removeConstraint(individualConstraint)
}
ticketsView.removeConstraints(ticketsView.constraints)
// self.view.removeConstraints(ticketsView.constraints)
if deviceSize.width < deviceSize.height {
print("TicketsView Constraint: Device is in PORTRAIT orientation!")
ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width).isActive = true
ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 ).isActive = true
ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0).isActive = true
ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.75).isActive = true
} else {
print("TicketsView Constraint: Device is in LANDSCAPE orientation!")
ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width).isActive = true
ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 ).isActive = true
ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0).isActive = true
ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.65).isActive = true
}
ticketsView.layoutIfNeeded()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (_) in
self.applyTicketsViewConstraints()
self.ticketsVC?.collectionView.reloadData()
}) { (_) in
self.ticketsView.layoutIfNeeded()
}
}
我希望我在上面的代码中创建的4个约束将被删除,以便可以使用不同的值重新创建它们。我似乎找不到消除它们的方法(有效)。上面的代码在上面的两行中注释掉,表明我也尝试了它们(未成功)。
答案 0 :(得分:1)
您可以尝试
var portrait = [NSLayoutConstraint]()
var landscape = [NSLayoutConstraint]()
let porCon1 = ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width)
let porCon2 = ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 )
let porCon3 = ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0)
let porCon4 = ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.75)
portrait = [porCon1,porCon2,porCon3,porCon4]
let landCon1 = ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width)
let landCon1 = ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 )
let landCon1 = ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0)
let landCon1 = ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.65)
landscape = [landCon1,landCon2,landCo3,landCon4]
func setPortrait(_ por:Bool) {
portrait.forEach { $0.isActive = por }
landscape.forEach { $0.isActive = !por }
}
也可能是
NSLayoutConstraint.deActivate(portrait)
NSLayoutConstraint.deActivate(landscape)
if por {
NSLayoutConstraint.activate(portrait)
}
else {
NSLayoutConstraint.activate(landscape)
}
答案 1 :(得分:0)
我认为您必须使用激活/停用约束,例如:
为其创建变量,并在setupConstrainsMethod中设置约束值。 var notRotatedYConstraint:NSLayoutConstraint!
var rotatedYConstraint: NSLayoutConstraint!
在viewdidload中: NSLayoutConstraint.activate([notRotatedYConstraint])
在您的功能中旋转iPhone的时间。 NSLayoutConstraint.deactivate([notRotatedYConstraint]) NSLayoutConstraint.activate([rotatedYConstraint])
答案 2 :(得分:0)
发布的前2个答案合起来可以为我提供所需的答案。 @Sh_Khan指示我使用NSLayoutConstraint数组。 @Wurzel指出,我应该使用NSLayoutConstraint.activate()和.deactivate()函数一次启用/禁用整个约束组。
因此,关键是将所有纵向约束添加到一个数组,将所有横向约束添加到另一个数组,然后每次方向改变时,我在两个数组上调用deactivate函数,然后重新创建并激活适当的数组。
(safeAreaLayoutGuide会在设备方向发生变化时发生变化,这就是为什么我无法预先预先创建两组约束的原因。我还想要一种在约束变得更加动态的情况下也可以使用的解决方案,例如响应给用户调整显示区域的大小)
我的原始代码现在变为:
func applyTicketsViewConstraints() {
let safe = self.view.safeAreaLayoutGuide
let deviceSize = UIScreen.main.bounds.size
NSLayoutConstraint.deactivate(portraitTicketsViewConstraints)
NSLayoutConstraint.deactivate(landscapeTicketsViewConstraints)
if deviceSize.width < deviceSize.height {
print("TicketsView Constraint: Device Size is in PORTRAIT orientation!")
portraitTicketsViewConstraints = [
ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width),
ticketsView.trailingAnchor.constraint(equalTo: safe.trailingAnchor, constant: 0 ),
ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0),
ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.75)
]
NSLayoutConstraint.activate(portraitTicketsViewConstraints)
} else {
print("TicketsView Constraint: Device Size is in LANDSCAPE orientation!")
landscapeTicketsViewConstraints = [
ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width),
ticketsView.trailingAnchor.constraint(equalTo: safe.trailingAnchor, constant: 0 ),
ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0),
ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.65)
]
NSLayoutConstraint.activate(landscapeTicketsViewConstraints)
}
ticketsView.layoutIfNeeded()
}
}