Understanding How to Move a View When a Keyboard Appears in iOS

Understanding the Problem

In this post, we will delve into a common issue faced by iOS developers when working with UIViewControllers 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