Xcode/iOS5: Move UIView up, when keyboard appears

64,668

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

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];
}

Solution 4

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 5

mark, apple document: Managing the keyboard - Moving Content That Is Located Under the Keyboard

Share:
64,668
filou
Author by

filou

Updated on February 18, 2020

Comments

  • filou
    filou about 4 years

    I'd like to move up my view, when the keyboard is shown. The keyboard (height: 216) should push up my view with it's height. Is this possible with a simple code?

  • James Webster
    James Webster over 12 years
    myView.center = //whatever your center was before + (CGPointMake(0, 216))
  • filou
    filou over 12 years
    Thank you madmw, this is perfect :)
  • djromero
    djromero almost 12 years
    @AlexisW did you change your mind to accept a less complete answer six months later or there is a glitch in SO? Weird.
  • filou
    filou almost 12 years
    it was not my intention to lower your reputation or even to disregard your detailed answer. Since I am here on stack I learned pretty much about programming. So when I need a function, I just search for it to learn. I also learned that sometimes simple answers or examples are more helpful to realise for "newbies". Thank you anyway for your help madmw.
  • djromero
    djromero almost 12 years
    I don't care very much about SO reputation, just trying to understand why did you pick an incorrect (IMHO of course) answer. Thanks for the clarification.
  • Mirror318
    Mirror318 about 11 years
    This is great, thanks! Changing the frame did some warping though, so I changed the center of self.view instead, and the animation smoothly moved the view with the keyboard :)
  • masonk
    masonk almost 11 years
    Your method of pushing the view worked whereas moving the center didn't work. (Moving the center pushed up, but when I moved it back, it pushed down too far).
  • James Paul Mason
    James Paul Mason over 10 years
    I just attempted to use this solution for a similar problem. There's one issue with this solution: you should set your originalCenter parameter in viewDidAppear rather than viewDidLoad. This is because UI elements have not been placed in their locations at this point in the cycle, but have been by viewDidAppear. originalCenter in viewDidLoad was giving me x=0, y=0.
  • sreekanthk
    sreekanthk almost 10 years
    pls guys help me solving this if anybody knows stackoverflow.com/questions/23670934/…
  • sosuke
    sosuke over 9 years
    Worked great for me thank you, I just dropped it in, set my UITextField delegates and it did the rest. Thanks!
  • Ankur
    Ankur about 9 years
    works perfect, one suggestion though, use block based animation instead begin/commitAnimation ...
  • Виктор Иванов
    Виктор Иванов over 8 years
    Perfect! And its really easy and quick to integrate in your existing code.
  • CQM
    CQM over 8 years
    what should y b? how do I calculate this minus the keyboard
  • Chen Li Yong
    Chen Li Yong about 8 years
    I agree. This is THE BEST and NEATEST solution on the planet. I don't even have to think about anything else, and it even integrates nicely with my textFieldShouldReturn (set a chain of the next of becomeFirstResponder using tag). Your solution still works even after 2 years from your original date of post. Thank you!
  • Naddy
    Naddy about 8 years
    This works fine. only caveat is that equal amount of portion gets hidden on top. How should I cover up for the lost area at the top?
  • Nike Kov
    Nike Kov about 6 years
    It makes a black area when keyboard is already hidden, but the view still animates.