【发布时间】:2023-04-02 08:53:01
【问题描述】:
我有 3 个带有编程约束的 UIView 层。
用于以编程方式设置约束的构造函数:
func setupViewConstraints(item:UIView, leadingTo:NSLayoutXAxisAnchor, leadingCon:CGFloat,
trailingTo:NSLayoutXAxisAnchor, trailingCon:CGFloat, topTo:NSLayoutYAxisAnchor,
topCon:CGFloat, bottomTo:NSLayoutYAxisAnchor, bottomCon:CGFloat) {
item.translatesAutoresizingMaskIntoConstraints = false
item.leadingAnchor.constraint(equalTo: leadingTo, constant: leadingCon).isActive = true
item.trailingAnchor.constraint(equalTo: trailingTo, constant: trailingCon).isActive = true
item.topAnchor.constraint(equalTo: topTo, constant:topCon).isActive = true
item.bottomAnchor.constraint(equalTo: bottomTo, constant:bottomCon).isActive = true
}
最低的基础层是浅灰色。
view = UIView()
view.backgroundColor = .lightGray
第 2 层包含 2 个UIView(红色和蓝色),带有约束。
let red = UIView()
red.backgroundColor = .red
view.addSubview(red)
setupViewConstraints(item: red, leadingTo: view.leadingAnchor, leadingCon: 0, trailingTo: view.trailingAnchor, trailingCon: -(view.frame.width)*0.2), topTo: view.topAnchor, topCon: 0, bottomTo: view.bottomAnchor, bottomCon: -(view.frame.width)*0.8)
let blue = UIView()
blue.backgroundColor = .blue
view.addSubview(blue)
setupViewConstraints(item: blue, leadingTo: view.leadingAnchor, leadingCon: 0, trailingTo: view.trailingAnchor, trailingCon: -(view.frame.width)*0.2), topTo: red.bottomAnchor, topCon: 0, bottomTo: view.bottomAnchor, bottomCon: 0)
在顶部我有黄色的UIView 层,它与所有较低的层重叠。
let yellow = UIView()
yellow.backgroundColor = .yellow
view.addSubview(yellow)
setupViewConstraints(item: yellow, leadingTo: view.leadingAnchor, leadingCon: 0, trailingTo: view.trailingAnchor, trailingCon: 0, topTo: view.topAnchor, topCon: 0, bottomTo: view.bottomAnchor, bottomCon: 0)
另外,我在黄色的UIView 中有UINavigationBar 和UINavigationItem。
//Add navigation item and buttons
naviItem = UINavigationItem()
naviItem.setRightBarButton(UIBarButtonItem(barButtonSystemItem:.add, target:self, action:#selector(goToDestVC)), animated: true)
naviItem.setLeftBarButton(UIBarButtonItem(image: UIImage(named: "hamburger_slim_30"), style: .plain, target: self, action: #selector(hamburgerBtnPressed)), animated: true)
//Add navigation bar with transparent background
naviBar = UINavigationBar()
naviBar.setBackgroundImage(UIImage(), for: .default)
naviBar.shadowImage = UIImage()
naviBar.isTranslucent = true
// Assign the navigation item to the navigation bar
naviBar.items = [naviItem]
view.addSubview(naviBar)
setupViewConstraints(item: naviBar, leadingTo: yellow.leadingAnchor, leadingCon: 0, trailingTo: yellow.trailingAnchor, trailingCon: 0, topTo: yellow.topAnchor, topCon: 0, bottomTo: yellow.bottomAnchor, bottomCon: -(view.frame.height)*0.9))
我有 hamburgerBtnPressed 函数,它应该将黄色层向右移动 80%(我将前导和尾随常量的值更改 80%),但这不起作用!!!
var hamburgerMenuIsVisible = false
@objc func hamburgerBtnPressed(_ sender: Any) {
if !hamburgerMenuIsVisible {
let menuWidth = (self.view.frame.width)*0.8
setupViewConstraints(item: layoutView, leadingTo: view.leadingAnchor, leadingCon: menuWidth, trailingTo: view.trailingAnchor, trailingCon: menuWidth, topTo: view.topAnchor, topCon: 0, bottomTo: view.bottomAnchor, bottomCon: 0)
hamburgerMenuIsVisible = true
} else {
setupViewConstraints(item: layoutView, leadingTo: view.leadingAnchor, leadingCon: 0, trailingTo: view.trailingAnchor, trailingCon: 0, topTo: view.topAnchor, topCon: 0, bottomTo: view.bottomAnchor, bottomCon: 0)
hamburgerMenuIsVisible = false
}
// layoutIfNeeded() lays out the subviews immediately and forces the layout before drawing
UIView.animate(withDuration: 0.2, delay:0.0, options: .curveEaseIn, animations: {
self.view.layoutIfNeeded()
}) { (animationComplete) in
print("Animation is complete!")
}
}
但是如果我将前导和尾随常量的值更改为负数,一切都会正常工作,菜单会向左移动而不会出现任何问题。
let menuWidth = -(self.view.frame.width)*0.8
请解释.. 有什么问题?为什么黄色UIView 向左移动,约束为负值,而约束为正值时不起作用?并给出错误:
Probably at least one of the constraints in the following list is one you don't want.
(
"<NSLayoutConstraint:0x6040002853c0 UIView:0x7fa947c35850.trailing == UIView:0x7fa947e1d2d0.trailing (active)>",
"<NSLayoutConstraint:0x604000092750 UIView:0x7fa947c35850.trailing == UIView:0x7fa947e1d2d0.trailing + 331.2 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x604000092750 UIView:0x7fa947c35850.trailing == UIView:0x7fa947e1d2d0.trailing + 331.2 (active)>
更新:我选择了选项2: 保留对要更改的约束的引用并调整其常量。在 layoutIfNeeded 之前也需要调用 setNeedsLayout。
更新代码:
var leadingC: NSLayoutConstraint!
var trailingC: NSLayoutConstraint!
var yellow: UIView!
加载视图():
yellow = UIView()
yellow.backgroundColor = .yellow
view.addSubview(yellow)
//Set up leading and trailing constraints for handling yellow view shift
leadingC = yellow.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0)
trailingC = yellow.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0)
//Put leadingC.constant and trailingC.constant into the function
setupViewConstraints(item: yellow, leadingTo: view.leadingAnchor, leadingCon: leadingC!.constant, trailingTo: view.trailingAnchor, trailingCon: trailingC.constant, topTo: view.topAnchor, topCon: 0, bottomTo: view.bottomAnchor, bottomCon: 0)
更新汉堡功能:
@objc func hamburgerBtnPressed(_ sender: Any) {
if !hamburgerMenuIsVisible {
let menuWidth = (self.view.frame.width)*0.8
leadingC!.constant = menuWidth
trailingC!.constant = menuWidth
print(leadingC.constant, trailingC.constant)
hamburgerMenuIsVisible = true
} else {
leadingC!.constant = 0
trailingC!.constant = 0
hamburgerMenuIsVisible = false
}
// layoutIfNeeded() lays out the subviews immediately and forces the layout before drawing
UIView.animate(withDuration: 0.2, delay:0.0, options: .curveEaseIn, animations: {
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}) { (animationComplete) in
print("Animation is complete!")
}
}
var hamburgerMenuIsVisible = false
我没有错误并且“动画完成!”也打印了,但屏幕上什么也没有发生,没有动画。
【问题讨论】:
-
这是我个人不将约束创建结合到一个通用函数的原因之一——太难破译了。首先,如果我没看错,红色、蓝色和灰色视图没有问题,对吧?如果是这样,请将它们从您的问题中删除,因为它会产生噪音。您是否尝试计算 80% 的帧以 (a) 移动或 (b) 缩小黄色视图?因为在前者中,您已经说过它有效 - 因为您正在移动前导/尾随锚。但是如果你想要后者,你需要改变宽度锚点——我在你的通用函数中没有看到。
-
我想将黄色 UIView 向右移动 80%,以便 (a) 移动黄色视图。我将尾随锚点用于“宽度”,我只能设置宽度或尾随锚点,否则会发生冲突。
-
正确。所以听起来你想要一个 static 宽度。这是混乱的一部分......(1)你为什么要计算帧宽度的 80%?那不会改变。更多,(2)要保持这个 static 宽度,您可以更改常量 - 可能它会与乘数一起使用,但我认为不会 - 前导 和 尾随负值向左移动/移动并返回其原始值以向右移动。我以为你说的有效?我错过了什么?
-
我正在计算帧宽度的 80%,因为它是第二层菜单的宽度,如果黄色视图向左移动 80%,它会打开隐藏菜单。宽度可以是任意的,问题不在于那个。在这种情况下,前导和尾随常量的默认值等于 0,我将值更改相同的量,在这种情况下(.trailing/leading + 331.2(视图宽度的 80%))并且黄色视图必须转换为正确的。 -->领先+331.2-->尾随+331.2。对于负值,它可以工作,并将黄色视图向左移动,但不适用于正值。
标签: ios swift constraints programmatically