1

I have a tableview that I've initialized with 4 constraints in the viewDidLoad() method. I wanted to programmatically change the bottomAnchor later in the code so I saved it as a variable bottomAnchor I then have another variable keyboardBottomAnchor for the changed constraint

These are the initial constraints:

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

Basically, I wanted the table view to go up when the keyboard open and back down when the keyboard closes. Here's how that looks:

@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
}

The keyboardAppears method is working (the table view goes up when the keyboard shows) but the keyboardDisappears method is giving me a Unable to simultaneously satisfy constraints error (aka it is saying that both bottomConstraint and keyboardBottomConstraint are active)

Any thoughts as to why this is happening?

UPDATE:

I used the .constant below (this works but only the first time I open up the keyboard)

@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)
        }
}
green
  • 77
  • 7
  • Creating a new constraint isn't necessary. Simply update the `constant` property of the constraint you already have. You can animate this change. – Paulw11 Oct 02 '20 at 21:40
  • Thanks that helped partially:) Now, it only work the first time I make the keyboard appear/disappear but doesn't work the second time around. Any idea why? – green Oct 02 '20 at 21:46
  • Did you set the constant back when the keyboard disappears? I can't say anything more without seeing your new code. What notifications are you observing? Have you set breakpoints or log statements to see what functions are being called? – Paulw11 Oct 02 '20 at 21:49
  • Not the answer to your question but if you want to have a view to avoid keyboard I suggest you to use [IHKeyboardAvoiding](https://github.com/IdleHandsApps/IHKeyboardAvoiding) – banderson Oct 02 '20 at 21:51
  • I added the code with the constants to the post, as mentioned this only works the first time around? Also, I'm observing `keyboardWillHideNotification` and `keyboardWillShowNotification` – green Oct 02 '20 at 21:56
  • @banderson Ill take a look, thanks – green Oct 02 '20 at 22:01

1 Answers1

0

Swift 5

Do not deactivate the constraint, just change its constant value.

I have written the code below and tested it, customize it as you like, will work perfectly with you!

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()
    }
}

Note: Do not forget to remove keyboard observers in deinit

Essam Fahmi
  • 1,920
  • 24
  • 31
  • Thank you - been stick on that awhile:) If possible I have a follow-up question: I want the table to scroll to the bottom when it goes up so I'm using tableView.scrollToRow. Sadly, it only works the first time around. – green Oct 02 '20 at 22:53
  • @green First of all, mark the answer accepted if it helped you. Regarding your question, please provide more details with code and I will help you. – Essam Fahmi Oct 02 '20 at 23:21
  • Marked it green! I just want to add `self.entrySpace.scrollToRow(at: IndexPath(row: self.data.count - 1, section: 0), at: .top, animated: true)` so that it scrolls the content up when the keyboard comes up - was wondering how to place it in the above? – green Oct 03 '20 at 00:06
  • Yes, you should mark the answer as accepted and vote it up if you can when you got your answer. Regarding your question, put your code in `keyboardWillShow` so that whenever the keyboard appears you scroll. – Essam Fahmi Oct 03 '20 at 00:12
  • Thanks, and I'll make sure to mark it going forward. I was still having trouble with the scrolling so I went ahead and created another question for it [here](https://stackoverflow.com/questions/64179760/how-do-i-get-scrolltorow-to-work-within-a-uitableview-on-keyboard-events). Thanks for the help! – green Oct 03 '20 at 01:02