Reputation: 271175
I am building an app. It needs to accept user input from some UITextField
s. And sometimes the keyboard will hide the text field so I need to move up the view when the keyboard CGRect
intersects with the text field's frame
.
I followed this tutorial an I added some of my own logic because I have multiple text fields.
Here is my relevant code: (The whole thing is in a VC that conforms to UITextFieldDelegate
)
var focusedTextField: UITextField?
var viewMovedUp = false
var keyboardSize: CGRect!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("onRotate:"), name:UIDeviceOrientationDidChangeNotification, object: nil);
}
override func viewDidDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
focusedTextField = textField
}
func onRotate (notification: NSNotification) {
view.endEditing(true)
}
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
self.keyboardSize = keyboardSize
assert(focusedTextField != nil)
if CGRectIntersectsRect(focusedTextField!.bounds, keyboardSize){
moveView(up: true)
}
}
}
}
func keyboardWillHide(notification: NSNotification) {
if viewMovedUp {
moveView(up: false)
}
}
func moveView (up up: Bool) {
let keyboardHeight = keyboardSize.height
let movement = (up ? -keyboardHeight : keyboardHeight)
UIView.animateWithDuration(0.3, animations: {
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
})
viewMovedUp = up
}
If you don't want to read the whole code, I'll explain the gist of it. So basically when the user taps on one of the text fields, textFieldDidBeginEditing
gets called. That basically sets the focusedTextField
to the text field that the user is editing. Then keyBoardWillShow
gets called. It gets the keyboard size and assign it to a class-level variable called keyboardSize
It then checks if the focused text field (remember that?) is covered by the keyboard (via CGRectIntersectRect
). If it is then we move the view up by calling moveView
. That method works perfectly fine so no need to explain.
Now on to the problem!
Let's look at a screen shot of the VC:
When I tap on the "Enter A" text field, the view moves up as expected. But when I tap on the "Enter P" text field, the keyboard shows up and covers the text field completely.
After some debugging, I found that
CGRectIntersectsRect(focusedTextField!.bounds, keyboardSize)
returns false
so moveView
is not called. The "Enter P" text field and keyboard size is as follows:
Bounds of text field:
x: 62 y: 94.5
height: 32.5 width: 278
Keyboard size:
x: 0 y: 158
height: 162 width: 568
Just from these figures, I don't think they overlap. But visually, they really do!
I also tried to change focusedTextField!.bounds
to focusedTextField.frame
but it still doesn't work.
Why is this happening? How do I fix it?
Upvotes: 1
Views: 649
Reputation: 535086
The problem is that in this code:
CGRectIntersectsRect(focusedTextField!.bounds, keyboardSize)
...you are comparing apples and oranges:
focusedTextField!.bounds
is in the coordinate space of focusedTextField
keyboardSize
is in the coordinate space of the window
(And the reason why focusedTextField.frame
didn't work is that it is in yet another coordinate space, that of the text field's superview.)
Those are two very different coordinate spaces, so you cannot compare these rects. You have to convert one of them to the coordinate space of the other.
For example, I think this will do it:
newKeyboardSize = focusedTextField.convertRect(keyboardSize, fromView:nil)
Now newKeyboardSize
and focusedTextField.bounds
should be in the same coordinate space.
Upvotes: 3