I have a UIView containing a UITextView. I want to move that UIView up when the keyboard is visible. So the idea is to change the Y position.
Sometimes, the UIView goes back to its initial Y position while the keyboard is still visible. And it doesn't come back anymore even if I focus the input. I really don't know why.
https://d17oy1vhnax1f7.cloudfront.net/items/2K0z3P1j1x2f0X2X1B2v/ci.gif
PS: The keyboard appears 3 times in the Gif. It is looping so it is hard to distinguish the end.
What I did, first I've added notification observer:
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChangeFrame), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
Then I've defined the keyboard toggle handler :
func keyboardWillChangeFrame(notification: NSNotification) {
let info = notification.userInfo!
let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
self.keyboardInfo["isVisible"] = self.view.frame.size.height - keyboardFrame.origin.y != 0
self.keyboardInfo["height"] = keyboardFrame.size.height
self.keyboardInfo["animationDuration"] = info[UIKeyboardAnimationDurationUserInfoKey] as! Double
self.keyboardInfo["animationCurve"] = info[UIKeyboardAnimationCurveUserInfoKey] as! UInt
if self.keyboardInfo["isVisible"] as! Bool {
self.moveCommentInputUp()
} else {
self.moveCommentInputDown()
}
}
After that, I've defined the methods which move up/down the comment input view:
func moveCommentInputUp() {
print("Moving up... ", self.commentFormView.frame.origin.y, " to ", self.view.frame.size.height - (self.keyboardInfo["height"] as! CGFloat) - self.commentFormView.frame.size.height)
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(self.keyboardInfo["animationDuration"] as! TimeInterval)
UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: Int(self.keyboardInfo["animationCurve"] as! UInt))!)
UIView.setAnimationBeginsFromCurrentState(true)
ViewUtil.changeViewFrame(view: self.commentFormView, yPosition: self.view.frame.size.height - (self.keyboardInfo["height"] as! CGFloat) - self.commentFormView.frame.size.height)
ViewUtil.removeShadowToView(self.commentFormLauncherButton)
UIView.commitAnimations()
}
func moveCommentInputDown() {
print("Moving down... ", self.commentFormView.frame.origin.y, " to ", self.view.frame.size.height)
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(self.keyboardInfo["animationDuration"] as! TimeInterval)
UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: Int(self.keyboardInfo["animationCurve"] as! UInt))!)
UIView.setAnimationBeginsFromCurrentState(true)
ViewUtil.changeViewFrame(view: self.commentFormView, yPosition: self.view.frame.size.height)
ViewUtil.addShadowToView(commentFormLauncherButton, position: CGSize(width: 0, height: 5))
UIView.commitAnimations()
}
The action of the button is
@IBAction func showCommentForm(_ sender: UIButton) {
self.commentInput.becomeFirstResponder()
}
Logs (please refer to the Gif) are showing that the view moves from 568 - bottom of the screen - to 568 again
// The numbers show the initial and the final value of the keyboard Y position
// Click on button to focus the input
Moving up... 568.0 to 282.0
// Tap anywhere
Moving down... 282.0 to 568.0
// Click again on button to focus the input
Moving up... 568.0 to 282.0
///// Write "hhh". The view is gone, I don't know why.
// Tap anywhere
Moving down... 568.0 to 568.0 // The view seems to move from 568 to 568, hugh
// Click on button to focus the input
Moving up... 568.0 to 282.0 // This didn't work apparently
// Tap anywhere
Moving down... 568.0 to 568.0 // 568 to 568 again
Did I miss something?
System: iOS 9, Xcode 8, Swift 3
Okay so this is a solution which doesn't require CocoaPods.
My approach involves setting the constant of the textField's bottom constraint when the keyboard appears and disappears. This means you need to create a reference to the textField's bottom constraint.
@IBOutlet weak var textFieldBottomConstraint: NSLayoutConstraint!
I started with setting the observers on NSNotification.Name.UIKeyboardWillShow and UIKeyboardWillHide in viewDidLoad, instead of UIKeyboardWillChangeFrame:
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
Next up I set the selector and its function to set the constant of the textField's bottom constraint:
func handleKeyboardNotification(notification: NSNotification) {
if let userInfo = notification.userInfo {
let keyboardFrameValue = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)
let keyboardFrame = keyboardFrameValue?.cgRectValue
let isKeyboardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
textFieldBottomConstraint.constant = isKeyboardShowing ? keyboardFrame!.height + 4 : 4
self.view.layoutIfNeeded()
}
}
Note that textFieldBottomConstraint is the reference variable to the bottom constraint.
What this does is makes textField set it's bottom constraint whenever the keyboard appears or disappears, and doesn't suffer from the weird glitches that you are experiencing.
Hope this helps and don't hesitate to ask for clarification!
Credits to YouTuber Let's Build that App! for providing the solution through this video:
https://www.youtube.com/watch?v=p8IaS5lmhuM
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With