我已经在 https://github.com/rDivaDuck/TestAppError 上创建了该问题的最小工作示例
我的 HomeController 是一个 UICollectioviewController,我有一个设置启动器类,我试图在导航栏按下按钮时从底部向上设置动画,我的代码通过停用向下约束并激活向上约束来实现此目的然后调用 window.layoutifneeded() 来动画更改。但是,我仍然抛出一个典型的约束冲突错误,即向下约束仍然处于事件状态。
我可以使用 .frame 和动画 CGRect 更改来实现良好的效果,但我想使用自动布局获得相同的效果。
class SettingsLauncher {
var homeController: HomeController?
let shadowView = UIView()
let MenuView: UIView = {
let View = UIView(frame: .zero)
View.backgroundColor = UIColor.white
View.translatesAutoresizingMaskIntoConstraints = false
return View
}()
var downConstraint: NSLayoutConstraint?
var upConstraint: NSLayoutConstraint?
func showSettings() {
if let window = UIApplication.shared.keyWindow{
shadowView.backgroundColor = UIColor(white: 0,
alpha: 0.4)
shadowView.addGestureRecognizer(UITapGestureRecognizer(target: self,
action: #selector(settingsDown)))
window.addSubview(shadowView)
shadowView.frame = window.frame
shadowView.alpha = 0
window.addSubview(MenuView)
downConstraint = MenuView.topAnchor.constraint(equalTo: window.bottomAnchor)
downConstraint?.isActive = true
upConstraint = MenuView.topAnchor.constraint(equalTo: window.bottomAnchor, constant: -300)
MenuView.heightAnchor.constraint(equalToConstant: 300).isActive = true
MenuView.leadingAnchor.constraint(equalTo: window.leadingAnchor).isActive = true
MenuView.trailingAnchor.constraint(equalTo: window.trailingAnchor).isActive = true
MenuView.layoutIfNeeded()
window.layoutIfNeeded()
settingsUp()
}
}
func settingsUp() {
downConstraint?.isActive = false
upConstraint?.isActive = true
UIView.animate(withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 1,
options: .curveEaseOut,
animations: {
self.shadowView.alpha = 1
if let window = UIApplication.shared.keyWindow {
window.layoutIfNeeded()
}
}, completion: nil)
}
@objc func settingsDown() {
downConstraint?.isActive = true
upConstraint?.isActive = false
UIView.animate(withDuration: 0.5,
animations: {
self.shadowView.alpha = 0
if let window = UIApplication.shared.keyWindow {
window.layoutIfNeeded()
}
}, completion: nil )
}
}
(
"<NSLayoutConstraint:0x600001b5e440 V:[UIWindow:0x7fde18514030]-(-300)-[UIView:0x7fde18525ea0] (active)>",
"<NSLayoutConstraint:0x600001b5f250 V:[UIWindow:0x7fde18514030]-(0)-[UIView:0x7fde18525ea0] (active)>"
)
我该如何解决这个问题?
最佳答案
您好,欢迎来到 StackOverflow,您的项目中存在多个错误。主要问题是,每次点击按钮并调用 showSettings()
时,都会向 MenuView 添加与之前的约束冲突的新约束,因此要解决此问题,您应该执行以下约束部分代码仅一次:
var viewInitialized = false
func showSettings() {
if let window = UIApplication.shared.keyWindow {
if !viewInitialized {
viewInitialized = true
shadowView.backgroundColor = UIColor(white: 0, alpha: 0.4)
shadowView.addGestureRecognizer(UITapGestureRecognizer(target: self,
action: #selector(settingsDown)))
window.addSubview(shadowView)
shadowView.frame = window.frame
shadowView.alpha = 0
window.addSubview(MenuView)
downConstraint = MenuView.topAnchor.constraint(equalTo: window.bottomAnchor)
downConstraint?.isActive = true
upConstraint = MenuView.topAnchor.constraint(equalTo: window.bottomAnchor, constant: -300)
MenuView.heightAnchor.constraint(equalToConstant: 300).isActive = true
MenuView.leadingAnchor.constraint(equalTo: window.leadingAnchor).isActive = true
MenuView.trailingAnchor.constraint(equalTo: window.trailingAnchor).isActive = true
MenuView.layoutIfNeeded()
window.layoutIfNeeded()
}
settingsUp()
}
}
此外,在 settingsDown()
中切换激活语句,以便您在激活另一个约束之前停用约束,有时这会导致警告。
@objc func settingsDown() {
upConstraint?.isActive = false
downConstraint?.isActive = true
...
我发现的项目的其他问题:
- 在
AppDelegate.swift
中为什么要创建一个新窗口?已经有一个,您可以使用它。删除这行无用的代码即可window = UIWindow(frame: UIScreen.main.bounds)
- 为什么要在
AppDelegate.swift
中创建导航 Controller ?将其作为第一个 View Controller 添加到 Storyboard 中。对于HomeController
来说也是如此,将 CollectionViewController 添加到 Storyboard并将其类更改为HomeController
- 将 View 直接添加到主窗口并不是一个好的做法。您应该将设置 View 呈现为模态视图 Controller ,并将呈现样式设置为当前上下文
- 在
SettingsLauncher.swift
中shadowView
缺少约束
关于ios - 即使调用 needforlayout() ,单独类中的动画自动布局约束也会引发错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52420536/