Xcode/iOS5: Move UIView up, when keyboard appears

Solution 1:

To move the view up, just change its center. First, keep the original one in a CGPoint property.

- (void)viewDidLoad 
{
    ...
    self.originalCenter = self.view.center;
    ...
}

Then, change as needed when keyboard shows up:

self.view.center = CGPointMake(self.originalCenter.x, /* new calculated y */);

Finally, restore it when keyboard is hidden:

self.view.center = self.originalCenter;

Add animation sugar as you wish

You have more than one way to know when the keyboard appears.

Observing UIKeyboardDidShowNotification notification.

/* register notification in any of your initWithNibName:bundle:, viewDidLoad, awakeFromNib, etc. */
{
    ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];     
    ...
}

- (void)keyboardDidShow:(NSNotification *)note 
{
    /* move your views here */
}

Do the opposite with UIKeyboardDidHideNotification.

-OR-

Implement UITextFieldDelegate

Detect when editing begin/end to move views around.

- (void)textFieldDidBeginEditing:(UITextField *)textField 
{
    /* keyboard is visible, move views */
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    /* resign first responder, hide keyboard, move views */
}

Depending on the actual text fields you may need to track in which field is the user editing, add a timer to avoid moving views too much.

Solution 2:

do like this. after keyboard visible use this code

- (void)textFieldDidBeginEditing:(UITextField *)textField 
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.25];
    self.view.frame = CGRectMake(0,-10,320,480);
    [UIView commitAnimations];

}

Solution 3:

I did this in a similar fashion to djromero except that I adjusted the frame origin of the view rather than its centre.

The view that i'm moving is a UIScrollView, and I want it to move relative to a UITextField element, so that the text field always shows. The position of this text field can vary depending on the offset of the scroll view.

So my code looks like this:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.2];
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
        self.scrollView.frame = CGRectMake(0,0,self.scrollView.frame.size.width,self.scrollView.frame.size.height);
        [UIView commitAnimations];
    });
    return YES;
}

- (NSInteger)getKeyBoardHeight:(NSNotification *)notification
{
    NSDictionary* keyboardInfo = [notification userInfo];
    NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
    NSInteger keyboardHeight = keyboardFrameBeginRect.size.height;
    return keyboardHeight;
}

-(void) keyboardDidShow:(NSNotification*) notification
{
    NSInteger keyboardHeight;
    keyboardHeight = [self getKeyBoardHeight:notification];
    NSInteger scrollViewFrameHeight = self.scrollView.frame.size.height;
    NSInteger textFieldRelativePosition = self.tableView.frame.origin.y - self.scrollView.contentOffset.y;
    NSInteger textFieldFrameOffset = scrollViewFrameHeight - textFieldRelativePosition;
    NSInteger movement = MAX(0,keyboardHeight-textFieldFrameOffset); // Offset from where the keyboard will appear.
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.2];
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
        self.scrollView.frame = CGRectMake(0,-movement,
                                           self.scrollView.frame.size.width,
                                           self.scrollView.frame.size.height);
        [UIView commitAnimations];
    });
}

The view controller is a UITextFieldDelegate and also subscribes to UIKeyboardDidShowNotification so that we are able to access the size of the keyboard.

When the keyboard shows, we calculate the relative offset of the UITextField (adjusted for scroll offset) and the keyboard and them change the origin of the UIScrollView so that it moves just enough for the UITextField still to be showing.

If the UITextField will still show even if the keyboard appears, then the origin does not change.

Solution 4:

This is the most easiest and efficient way to achieve this:

Add the following constants:

static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;    

Add this to your view controller:

CGFloat animatedDistance;

And add these methods to your code:

- (void)textFieldDidBeginEditing:(UITextField *)textField{
CGRect textFieldRect =
[self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect =
[self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator =
midline - viewRect.origin.y
- MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator =
(MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
    heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
    heightFraction = 1.0;
}
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
    orientation == UIInterfaceOrientationPortraitUpsideDown)
{
    animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
    animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

[self.view setFrame:viewFrame];

[UIView commitAnimations];
}

- (void)textFieldDidEndEditing:(UITextField *)textfield{

CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

[self.view setFrame:viewFrame];

[UIView commitAnimations];
}