0

on a function I have titled handleKeyboardWillShow, my input textfield is moving higher than expected. It is my intention for the textfield to be pinned to the top of the keyboard view. I have also added the code to the creation of the text field that seems to be causing the issue.

Here is an image depicting my error

Creation of the textField variable

  lazy var inputTextField: UITextField = {
    let tf = UITextField()
    tf.placeholder = "Enter message..."
    tf.translatesAutoresizingMaskIntoConstraints = false
    tf.delegate = self
    return tf
}()

My view did load function

    override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
    collectionView.alwaysBounceVertical = true
    collectionView.register(ChatMessageCell.self, forCellWithReuseIdentifier: cellId)
    collectionView.backgroundColor = .white
    collectionView.keyboardDismissMode = .interactive
    becomeFirstResponder()
    setUpInputComponents()
    setUpKeyboardObserver()

}

View will disappear is where I remove the observers

 override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    //MARK: IMPORTANT FOR SHOWING AND HIDING KEYBOARD TO AVOID MEMORY LEAKS
    NotificationCenter.default.removeObserver(self)
}

func setUpKeyboardObserver(){
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

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

@objc func handleKeyboardWillShow(notification:NSNotification){
    let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
            let keyboardDuration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue
    let safeLayoutGuideBot = UIApplication.shared.keyWindow?.safeAreaInsets.bottom
    let height =  (keyboardFrame?.height)! - safeLayoutGuideBot!
    containerViewBottomAnchor?.constant = -height
    UIView.animate(withDuration: keyboardDuration!, animations: {
        self.view.layoutIfNeeded()
    })
}

@objc func handleKeyboardWillHide(notification:NSNotification){
    let keyboardDuration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue
    containerViewBottomAnchor?.constant = 0
    UIView.animate(withDuration: keyboardDuration!, animations: {
        self.view.layoutIfNeeded()
    })
}

This is where the layout for the textView in question and container view are set up.

var containerViewBottomAnchor: NSLayoutConstraint?

func setUpInputComponents(){
    let containerView = UIView()
    containerView.translatesAutoresizingMaskIntoConstraints = false
    containerView.backgroundColor = .white
    view.addSubview(containerView)

    containerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    containerViewBottomAnchor =  containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    containerViewBottomAnchor?.isActive = true
    containerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    containerView.heightAnchor.constraint(equalToConstant: 50).isActive = true

    containerView.addSubview(sendButton)
    sendButton.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
    sendButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
    sendButton.widthAnchor.constraint(equalToConstant: 80).isActive = true
    sendButton.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true

    containerView.addSubview(inputTextField)
    inputTextField.leftAnchor.constraint(equalToSystemSpacingAfter: containerView.leftAnchor, multiplier: 8).isActive = true
    inputTextField.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
    inputTextField.rightAnchor.constraint(equalTo: sendButton.leftAnchor).isActive = true
    inputTextField.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true

    containerView.addSubview(seperatorLineView)
    seperatorLineView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
    seperatorLineView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
    seperatorLineView.widthAnchor.constraint(equalTo: containerView.widthAnchor).isActive = true
    seperatorLineView.heightAnchor.constraint(equalToConstant: 0.5).isActive = true
}

2 Answers2

0

It looks like you may be double counting the safe area. You should be able to just convert the keyboard's frame into your view's coordinate space and be done. Here's what my keyboard code looks like. Yours will be slightly different because you're using auto layout instead of frame based layout.

@objc func keyboardShown(_ notification: Notification) {
    let keyboardEndFrameWindow = (notification as NSNotification).userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue
    let keyboardTransitionDuration = (notification as NSNotification).userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
    let keyboardTransitionAnimationCurve = (notification as NSNotification).userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber

    let keyboardEndFrameView = self.view.convert(keyboardEndFrameWindow.cgRectValue, from:nil)
    var offsetY = keyboardEndFrameView.minY - self.nameField.frame.maxY;
    offsetY = min(offsetY, 0);

    UIView.animate(withDuration: TimeInterval(keyboardTransitionDuration.doubleValue),
        delay: 0.0,
        options: UIView.AnimationOptions(rawValue: keyboardTransitionAnimationCurve.uintValue),
        animations: { () -> Void in
            self.view.frame = self.view.frame.offsetBy(dx: 0, dy: offsetY)
    }, completion: nil)
}
InkGolem
  • 2,662
  • 1
  • 15
  • 22
0

Perhaps this fix was a hack, but I resolved it by implementing the following

        containerViewBottomAnchor?.constant -= (keyboardFrame?.height)! - 100

Statically subtracting the value of 100 from the keyboard frame height.