当我以编程方式更改约束时 Xcode 给出错误

Posted

技术标签:

【中文标题】当我以编程方式更改约束时 Xcode 给出错误【英文标题】:Xcode giving error when I programmatically change constraints 【发布时间】:2020-10-02 21:13:18 【问题描述】:

我有一个表视图,我在 viewDidLoad() 方法中使用 4 个约束进行了初始化。我想稍后在代码中以编程方式更改 bottomAnchor,所以我将其保存为变量 bottomAnchor 然后我有另一个变量 keyboardBottomAnchor 用于更改的约束

这些是初始约束:

tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 50).isActive = true
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
bottomAnchor = tableViewe.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant:  (-1) * card.cardHandleAreaHeight + -20)
bottomAnchor.isActive = true

基本上,我希望表格视图在键盘打开时上升,在键盘关闭时返回。看起来是这样的:

@objc func keyboardAppears(notification: Notification) 
        let userInfo = notification.userInfo
        keyboardFrame = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
       
        //this is the original constraint
        self.bottomConstraint.isActive = false
        //Here I make a new variable to save the new constraint
        keyboardBottomConstraint = tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -1 * keyboardFrame.height)
        keyboardBottomConstraint.isActive = true


@objc func keyboardDisappears(notification: Notification) 
        NSLayoutConstraint.deactivate([keyboardBottomConstraint])
        bottomConstraint.isActive = true

keyboardAppears 方法正在工作(当键盘显示时,表格视图会上升)但keyboardDisappears 方法给我一个Unable to simultaneously satisfy constraints 错误(也就是说bottomConstraintkeyboardBottomConstraint 都是主动)

对为什么会发生这种情况有任何想法吗?

更新:

我使用了下面的.constant(这有效,但仅在我第一次打开键盘时)

@objc func keyboardAppears(notification: Notification) 
        let userInfo = notification.userInfo
        var keyboardFrame = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
        
        bottomConstraint.constant = -1 * keyboardFrame.height
        tableView.scrollUp()


@objc func keyboardDisappears(notification: Notification) 
        returnOriginalConstraint()


func returnOriginalConstraint() 
        bottomAnchor.constant = (-1) * buttonCard.cardHandleAreaHeight + -20


//scrolling method
func scrollUp() 
        DispatchQueue.main.async 
            self.entrySpace.scrollToRow(at: IndexPath(row: self.data.count - 1, section: 0), at: .top, animated: true)
        

【问题讨论】:

不需要创建新的约束。只需更新您已有的约束的 constant 属性。您可以为这种变化设置动画。 感谢部分帮助:) 现在,它仅在我第一次使键盘出现/消失时起作用,但第二次不起作用。知道为什么吗? 当键盘消失的时候你有没有把常数设回去?如果没有看到您的新代码,我不能再说什么。您正在观察哪些通知?您是否设置了断点或日志语句以查看正在调用的函数? 不是您问题的答案,但如果您想避免使用键盘,我建议您使用IHKeyboardAvoiding 我在帖子中添加了带有常量的代码,如前所述,这仅在第一次有效?另外,我正在观察keyboardWillHideNotificationkeyboardWillShowNotification 【参考方案1】:

斯威夫特 5

不要停用约束,只需更改其常量值。

我已经编写了下面的代码并对其进行了测试,根据您的喜好自定义它,将与您完美配合!

import UIKit

class ViewController: UIViewController

    // MARK: Properties

    var tableView: UITableView!
    var tableBottomConstraint: NSLayoutConstraint!

    // MARK: View Controller Life Cycle

    override func viewDidLoad()
    
        super.viewDidLoad()
        addKeyboardObservers()
        setupTableView()
    

    deinit
    
        removeKeyboardObservers()
    

    // MARK: Methods

    private func addKeyboardObservers()
    
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillShow(notification:)),
                                               name: UIResponder.keyboardWillShowNotification,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillHide(notification:)),
                                               name: UIResponder.keyboardWillHideNotification,
                                               object: nil)
    

    private func removeKeyboardObservers()
    
        NotificationCenter.default.removeObserver(self,
                                                  name: UIResponder.keyboardWillShowNotification,
                                                  object: nil)

        NotificationCenter.default.removeObserver(self,
                                                  name: UIResponder.keyboardWillHideNotification,
                                                  object: nil)
    

    private func setupTableView()
    
        tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)

        tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true
        tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true

        tableBottomConstraint = tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50.0)
        tableBottomConstraint.isActive = true
    

    // MARK: Keyboard Handling

    @objc func keyboardWillShow(notification: Notification)
    
        if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
        
            tableBottomConstraint.constant = -1 * keyboardFrame.height
            loadViewIfNeeded()
        
    

    @objc func keyboardWillHide(notification: Notification)
    
        tableBottomConstraint.constant = -50.0
        loadViewIfNeeded()
    

注意:不要忘记删除deinit中的键盘观察者

【讨论】:

谢谢 - 坚持了一段时间:) 如果可能的话,我有一个后续问题:我希望表格在上升时滚动到底部,所以我使用的是 tableView.scrollToRow。遗憾的是,它只能在第一次使用。 @green 首先,如果对您有帮助,请标记已接受的答案。关于您的问题,请提供更多详细信息和代码,我会帮助您。 标记为绿色!我只想添加 self.entrySpace.scrollToRow(at: IndexPath(row: self.data.count - 1, section: 0), at: .top, animated: true) 以便在键盘出现时向上滚动内容 - 想知道如何将它放在上面? 是的,您应该将答案标记为已接受,并在您得到答案时投票。关于您的问题,请将您的代码放在keyboardWillShow 中,这样每当键盘出现时您就可以滚动。 谢谢,我会确保继续标记它。我仍然在滚动时遇到问题,所以我继续为它创建了另一个问题here。感谢您的帮助!

以上是关于当我以编程方式更改约束时 Xcode 给出错误的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式设置scrollview高度

当我以编程方式更改用户控件时,如何让数据绑定双向工作?

UITableViewCell 类布局无法以编程方式工作

X 位置约束未以编程方式更新 - Xcode 中的 Swift

为啥我以编程方式创建的视图会忽略其约束?

以编程方式将视图添加到垂直堆栈视图打破了垂直堆栈视图的约束