Link for previous question:
UITextField text jumps
Briefly:
I have ViewController
with 2 UITextField
elements. When loginField is firstResponder, after
self.passwordField.becomeFirstResponder()
text in login field jumps to the top left corner and back. And what's more strange: this glitch reproduces only first time, then you need recreate ViewController
to observe this behavior
Here is video of the glitch http://tinypic.com/player.php?v=6nsemw%3E&s=8#.VgVb3cuqpHx
I ended up with this (doesn't work for iOS 9):
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField === self.loginField {
self.loginField.resignFirstResponder()
// Shitty workaround. Hi, Apple!
self.loginField.setNeedsLayout()
self.loginField.layoutIfNeeded()
self.passwordField.becomeFirstResponder()
return false
}
return true
}
Is there anybody who has been stucked with this bug? Any suggestions?
Keyboard notifications handlers
My main view is UIScrollView, for which I change bottom space to superview, so user can scroll all the content even when keyboard is shown
func keyboardWillShow(notification : NSNotification) {
let keyboardInfo = notification.userInfo!
let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue
let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue!
UIView.animateWithDuration(animDuration, animations: {
self.scrollViewBottom.constant = keyboardFrame.height
self.view.layoutIfNeeded()
let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height
if offsetY > 0 {
self.scrollView.contentOffset = CGPointMake(0, offsetY)
}
})
}
func keyboardWillHide(notification : NSNotification) {
self.scrollViewBottom.constant = 0
self.view.layoutIfNeeded()
}
As I discovered keyboard notifications in iOS7, 8 and 9 very differ. So, in iOS 9 notifications are sent while changing firstResponder even if keyboard will not Show/Hide. Also, when I change firstResponder with tapping on textField (not tapping Next on keyboard which is handled by my code), there is only KeyboardWillShow notification and no KeyboardWillHide. And as for me, userInfo has some trash frame values, here is log when changing first responder using next button (works ok, without glitches):
2015-10-07 12:54:13.870 keyboardWillHide:
[UIKeyboardFrameBeginUserInfoKey: NSRect: {{0, 352}, {320, 216}},
UIKeyboardCenterBeginUserInfoKey: NSPoint: {160, 460},
UIKeyboardFrameEndUserInfoKey: NSRect: {{0, 568}, {320, 216}},
UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 676},
UIKeyboardAnimationDurationUserInfoKey: 0.25,
UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect:
{{0, 0}, {320, 216}}, UIKeyboardAnimationCurveUserInfoKey: 7]
2015-10-07 12:54:13.896 keyboardWillShow:
[UIKeyboardFrameBeginUserInfoKey: NSRect: {{0, 352}, {320, 216}},
UIKeyboardCenterBeginUserInfoKey: NSPoint: {160, 460},
UIKeyboardFrameEndUserInfoKey: NSRect: {{0, 352}, {320, 216}},
UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 460},
UIKeyboardAnimationDurationUserInfoKey: 0.25,
UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect:
{{0, 0}, {320, 216}}, UIKeyboardAnimationCurveUserInfoKey: 7]
And here is log when I tap on the second textField:
2015-10-07 12:55:13.879
keyboardWillShow:[UIKeyboardFrameBeginUserInfoKey: NSRect: {{0, 352},
{320, 216}}, UIKeyboardCenterBeginUserInfoKey: NSPoint: {160,
460}, UIKeyboardFrameEndUserInfoKey: NSRect: {{0, 352}, {320,
216}}, UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 460},
UIKeyboardAnimationDurationUserInfoKey: 0.25,
UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect:
{{0, 0}, {320, 216}}, UIKeyboardAnimationCurveUserInfoKey: 7]
Resolution
I discovered that I have another Keyboard Controller that receives keyboard notifications and make some animations. That's where the problem lies
Best Answer
Based on your edited question I can see this, when you tap next button on keyboard:
resignFirstResponder()
and thenbecomeFirstResponder()
. This callskeyboardWillHide
notification and thenkeyboardWillShow
notificationkeyboardWillHide
you haveself.view.layoutIfNeeded()
which layouts the view (and subviews - textfields) without animation.Because of this the textfield layout is "fixed" and when you do animation in
keyboardWillShow
the text in textfield doesn't "jump" anymore, because you did layout inkeyboardWillHide
.But when you just tap another textfield, only
keyboardWillShow
is called, layout is not "fixed" in textfield and when you animate the view, the text does a "jump" animation.That's why it doesn't jump when you tap next on keyboard but it does jump when you just tap another textfield.
So I would advise to change it to this: