Understanding the Problem
In this post, we will delve into a common issue faced by iOS developers when working with UIViewController
s and keyboards. The problem is that when the keyboard appears, it can cause the background view to scroll down below the keyboard, effectively hiding a view on top of it.
What’s Happening Under the Hood?
To understand why this happens, let’s take a look at how the iPhone handles keyboard events.
When the user presses a key, the iPhone sends a notification to the application that the keyboard is about to appear or disappear. These notifications are sent through UIKeyboardWillShowNotification
and UIKeyboardWillHideNotification
, respectively.
In our case, we’re interested in understanding how these notifications are handled by the system and how we can intercept them to move our background view accordingly.
The Role of Notifications
Notifications play a crucial role in allowing our application to respond to keyboard events. When a notification is received, it’s passed through a series of layers before reaching our code. This includes the app delegate, which is responsible for handling notifications and sending them to their respective handlers.
In this case, we’re using the UIKeyboardWillShowNotification
and UIKeyboardWillHideNotification
types, which are sent directly to the application delegate’s method.
Implementing a Solution
To move our background view when the keyboard appears or disappears, we need to implement two methods: keyboardWillShow:
and keyboardWillHide:
. These methods will be responsible for calculating the new frame of the background view based on the keyboard’s size.
Calculating the Keyboard Bounds
To calculate the keyboard bounds, we use the UIKeyboardFrameBeginUserInfoKey
key, which returns a value that contains the keyboard’s size.
- (void)keyboardWillShow:(NSNotification *)note {
// Get the keyboard bounds from the userInfo dictionary
NSValue *aValue = [note.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey];
[aValue getValue:&keyboardBounds];
// Store the keyboard height for later use
keyboardHeight = keyboardBounds.size.height;
}
Adjusting the Background View’s Frame
To adjust the background view’s frame, we need to calculate the new size of the view based on the keyboard bounds. We’ll subtract the keyboard’s size from the view’s current size to move it down.
- (void)keyboardWillShow:(NSNotification *)note {
// ...
if (!keyboardIsShowing) {
keyboardIsShowing = YES;
// Calculate the new frame of the background view
CGRect frame = view.frame;
frame.size.height -= 168; // Adjust for the status bar and navigation bar
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
view.frame = frame;
[UIView commitAnimations];
}
}
Animating the Frame Change
To animate the change in frame, we use a simple UIView
animation. We create an animation context, set the animation duration, and then commit it.
- (void)keyboardWillShow:(NSNotification *)note {
// ...
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
view.frame = frame;
[UIView commitAnimations];
}
Combining the Code
Here’s the complete code snippet that combines all the steps we’ve discussed:
- (void)viewDidAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)note {
// Get the keyboard bounds from the userInfo dictionary
NSValue *aValue = [note.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey];
[aValue getValue:&keyboardBounds];
// Store the keyboard height for later use
keyboardHeight = keyboardBounds.size.height;
if (!keyboardIsShowing) {
keyboardIsShowing = YES;
// Calculate the new frame of the background view
CGRect frame = view.frame;
frame.size.height -= 168; // Adjust for the status bar and navigation bar
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
view.frame = frame;
[UIView commitAnimations];
}
}
- (void)keyboardWillHide:(NSNotification *)note {
// Get the keyboard bounds from the userInfo dictionary
NSValue *aValue = [note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
[aValue getValue:&keyboardBounds];
// Store the keyboard height for later use
keyboardHeight = keyboardBounds.size.height;
if (keyboardIsShowing) {
keyboardIsShowing = NO;
// Calculate the new frame of the background view
CGRect frame = view.frame;
frame.size.height += 168; // Adjust for the status bar and navigation bar
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
view.frame = frame;
[UIView commitAnimations];
}
}
Last modified on 2025-05-06