With the iPhone SDK:

I have a UIView with UITextFields that brings up a keyboard. I need it to be able to:

  1. Allow scrolling of the contents of the UIScrollView to see the other text fields once the keyboard is brought up

  2. Automatically "jump" (by scrolling up) or shortening

I know that I need a UIScrollView. I've tried changing the class of my UIView to a UIScrollView but I'm still unable to scroll the textboxes up or down.

Do I need both a UIView and a UIScrollView? Does one go inside the other? [EDIT: I now know that you want a UIView inside of a UIScrollView, and the trick is to programatically set the content size of the UIScrollView to the frame size of the UIView.]

Then what needs to be implemented in order to automatically scroll to the active text field?

Ideally as much of the setup of the components as possible will be done in Interface Builder. I'd like to only write code for what needs it.

Note: the UIView (or UIScrollView) that I'm working with is brought up by a tabbar (UITabBar), which needs to function as normal.


Edit: I am adding the scroll bar just for when the keyboard comes up. Even though it's not needed, I feel like it provides a better interface because then the user can scroll and change textboxes, for example.

I've got it working where I change the frame size of the UIScrollView when the keyboard goes up and down. I'm simply using:

-(void)textFieldDidBeginEditing:(UITextField *)textField { 
    //Keyboard becomes visible
    scrollView.frame = CGRectMake(scrollView.frame.origin.x, 
                     scrollView.frame.origin.y, 
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50);   //resize
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
   //keyboard will hide
    scrollView.frame = CGRectMake(scrollView.frame.origin.x, 
       scrollView.frame.origin.y, 
     scrollView.frame.size.width,
      scrollView.frame.size.height + 215 - 50); //resize
}

However this doesn't automatically "move up" or center the lower text fields in the visible area, which is what I would really like.

upvote
  flag
you can use animation on textfield so that textfield moves when keyboard comes up – Pankaj Kainthla
4 upvote
  flag
Check this out. No hassle for you. TPKeyboardAvoiding – ArunaFromLK
17 upvote
  flag
It´s documented by Apple, I think it's the best way: developer.apple.com/library/ios/#documentation/StringsTextFo‌​nts/… – Maik639
upvote
  flag
Auto layout and Keyboard sensitive layout, by ghawk.gu The article also covers how to deal with portrait and landscape orientations. – neoneye
upvote
  flag
The below link explains how to scroll a view to show fields including UITextField hidden by keyboard very clearly with clear code and diagrams Click me 1 The below git hub link gives a running source code Click me 2 – Durai Amuthan.H
upvote
  flag
A very good tutorial with images is at: cocoawithlove.com/2008/10/… – iGodric
upvote
  flag
This is nice solution worked for me : github.com/simonbs/BSKeyboardControls – NSS
upvote
  flag
@Altaveron Apple should also start making apps for us. – Alex Markman
49 upvote
  flag
Use this code.You just need 1 line in appdelegate.m file and it works. github.com/hackiftekhar/IQKeyboardManager – Pradeep Mittal
9 upvote
  flag
The best way I found so far is this open source TPKeyboardAvoiding – Mongi Zaidi
upvote
  flag
IQKeyboardManager not working for 4s protraite mode – Sofeda
upvote
  flag
This solutions was better for me : //allinonescript.com/a/15036744/1234031 – Julian Corrêa
upvote
  flag
UITableViewController with UITextFields inside static cells would be a nice solution for this kind of requirements.Give it a try,You just loves that really – Naresh Reddy M
upvote
  flag
For anyone using a storyboard and trying to make it work but can't, just make sure that self.view has leading, top and trailing constraints defined. Otherwise, it probably won't work for IQKeyboardManager or for answers below. – Burak
upvote
  flag
Swift 3.0 version of apples keyboard management code is here : medium.com/@abhimuralidharan/… – abhi1992
upvote
  flag
Possible duplicate of Resize the screen when keyboard appears – Fattie
1 upvote
  flag
Another way is to add such contents text fields and all in TableViewController and let tableview handle this. – Vicky Dhas

85 Answers 11

up vote 931 down vote accepted
  1. You will only need a ScrollView if the contents you have now do not fit in the iPhone screen. (If you are adding the ScrollView as the superview of the components. just to make the TextField scroll up when keyboard comes up, then it's not needed.)

  2. For showing the textfields without being hidden by the keyboard, the standard way is to move up/down the view having textfields whenever the keyboard is shown.

Here is some sample code:

#define kOFFSET_FOR_KEYBOARD 80.0

-(void)keyboardWillShow {
    // Animate the current view out of the way
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)keyboardWillHide {
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:mailTf])
    {
        //move the main view, so that the keyboard does not hide it.
        if  (self.view.frame.origin.y >= 0)
        {
            [self setViewMovedUp:YES];
        }
    }
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3]; // if you want to slide up the view

    CGRect rect = self.view.frame;
    if (movedUp)
    {
        // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
        // 2. increase the size of the view so that the area behind the keyboard is covered up.
        rect.origin.y -= kOFFSET_FOR_KEYBOARD;
        rect.size.height += kOFFSET_FOR_KEYBOARD;
    }
    else
    {
        // revert back to the normal state.
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
    }
    self.view.frame = rect;

    [UIView commitAnimations];
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}
3 upvote
  flag
What does _textField? I copied it into my code, it says _textField is undeclared. – Cocoa Dev
upvote
  flag
It's the field that you use to say "when the user is editing here the view should slide up" or something so... However you can remove that if, if you more fields. – patrick
upvote
  flag
isn't it batter to call -(void)setViewMovedUp:(BOOL)movedUp in keyBoardWillSHow and KeyBoardWillHide events!! – Abduliam Rehmanius
upvote
  flag
Is the benefit of this example over the next that it does not require a UIScrollView? I don't want to have to put the contents of the view in an otherwise useless UIScrollView if its not necessary. – Michael
upvote
  flag
getting issue on UIInterfaceOrientationLandscapeRight and UIInterfaceOrientationLandscapeLeft . . . . My application work only in Landscape – Amit Battan
upvote
  flag
self is undefined for me. =/ – lolol
3 upvote
  flag
Not particularly useful if you're supporting rotations of the main view. – FiddleMeRagged
upvote
  flag
I like your solution but I think I can make it even simpler: don't bother with the Notification Observer stuff; instead call the right animation routines inside the appropriate delegate methods -- for UITextView they're textViewDidBeginEditing and textViewDidEndEditing. – AlexChaffee
upvote
  flag
This code works for textfields but does'nt work for uitextview.The textview is at the bottom of my screen, I want to move it up when the keyboard appears – zzzzz
upvote
  flag
Definitely don't change Y -- must change height! – Jeff
upvote
  flag
if keyboard is open then i go to background and i come back to foreground then keyboard is open but frame of view is not set in old position.what is the reason? – IKKA
upvote
  flag
You don't need to paste the - (void)viewWillAppear:(BOOL)animated method at all. It just spoils everything. – ZviBar
upvote
  flag
Use NPKeyboardLayoutGuide if you are using AutoLayout. – Puttin
upvote
  flag
I think you meant to give that compiler-constant a different name; prefixing it with a lower-case k implies it's a key, but you're using it as a naked constant. – Ben Leggiero
upvote
  flag
Not working with multiple texfiels – Rincha
upvote
  flag
@user1519240: That post worked for me after commenting out !CGRectContainsPoint(aRect, activeField!.frame.origin). Thanks :) – W.K.S
upvote
  flag
For anyone using a storyboard and trying to make it work but can't, just make sure that self.view has leading, top and trailing constraints. Otherwise, it probably won't work. – Burak
upvote
  flag
To make this work, I had to comment out the textFieldDidBeginEditing section. – avance
upvote
  flag
Please update the code with Swift ver. – Nitesh
upvote
  flag
my top textfield's are hidden when the keyboard is shown because,it is working not only for that particular textfield i'm giving but also for all the textfields i have . how do i fix it – Purushothaman
upvote
  flag
Didn't work for me. If it doesn't work for you, I recommend adding a scroll view in your storyboard around the pieces that you want to move (consider that carefully) and using the Apple code here: developer.apple.com/library/content/documentation/… with one modification: use UIKeyboardWillShowNotification instead of UIKeyboardDidShowNotification. That improvement will eliminate a lag you get before the scrolling starts. – Andy Weinstein
upvote
  flag
Bad for using hardcoded keyboard size. – Jonny
1 upvote
  flag
This answer is all of completely useless, remarkably out of date, and funny :) The only modern solution is something like this ... //allinonescript.com/a/41808338/294884 – Fattie

One thing to consider is whether you ever want to use a UITextField on its own. I haven’t come across any well-designed iPhone apps that actually use UITextFields outside of UITableViewCells.

It will be some extra work, but I recommend you implement all data entry views a table views. Add a UITextView to your UITableViewCells.

1 upvote
  flag
One of my apps needs to allow users to add freeform notes- so yes it is sometimes useful to use a UITextField. – Peter Johnson
1 upvote
  flag
I agree with this method. Zero work or code this way. Even if you need a free form note you still can with a table cell – RJH
upvote
  flag
UITableView is sadly the only way to go. Keyboard notifications are brittle and have changed overtime. Sample code on Stack Overflow: //allinonescript.com/a/32390936/218152 – SwiftArchitect
upvote
  flag
This answer is some five years out of date. The only modern solution is something like this ... //allinonescript.com/a/41808338/294884 – Fattie

see UICatalogView examples of iphone live and loaded

I'm not sure if moving the view up is the correct approach, I did it in a differente way, resizing the UIScrollView. I explained it in details on a little article

RPDP's code successfully moves the text field out of the way of the keyboard. But when you scroll to the top after using and dismissing the keyboard, the top has been scrolled up out of the view. This is true for the Simulator and the device. To read the content at the top of that view, one has to reload the view.

Isn't his following code supposed to bring the view back down?

else
{
    // revert back to the normal state.
    rect.origin.y += kOFFSET_FOR_KEYBOARD;
    rect.size.height -= kOFFSET_FOR_KEYBOARD;
}

To bring back to original view state, add:

-(void)textFieldDidEndEditing:(UITextField *)sender

{
    //move the main view, so that the keyboard does not hide it.
    if  (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

Little fix that works for many UITextFields

#pragma mark UIKeyboard handling

#define kMin 150

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
   if (currTextField) {
      [currTextField release];
   }
   currTextField = [sender retain];
   //move the main view, so that the keyboard does not hide it.
   if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {
        [self setViewMovedUp:YES]; 
   }
}



//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
   [UIView beginAnimations:nil context:NULL];
   [UIView setAnimationDuration:0.3]; // if you want to slide up the view

   CGRect rect = self.view.frame;
   if (movedUp)
   {
      // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
      // 2. increase the size of the view so that the area behind the keyboard is covered up.
      rect.origin.y = kMin - currTextField.frame.origin.y ;
   }
   else
   {
      // revert back to the normal state.
      rect.origin.y = 0;
   }
   self.view.frame = rect;

   [UIView commitAnimations];
}


- (void)keyboardWillShow:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

   if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin)
   {
      [self setViewMovedUp:YES];
   }
   else if (![currTextField isFirstResponder] && currTextField.frame.origin.y  + self.view.frame.origin.y < kMin)
   {
      [self setViewMovedUp:NO];
   }
}

- (void)keyboardWillHide:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
   if (self.view.frame.origin.y < 0 ) {
      [self setViewMovedUp:NO];
   }

}


- (void)viewWillAppear:(BOOL)animated
{
   // register for keyboard notifications
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) 
                                                name:UIKeyboardWillShowNotification object:self.view.window]; 
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) 
                                                name:UIKeyboardWillHideNotification object:self.view.window]; 
}

- (void)viewWillDisappear:(BOOL)animated
{
   // unregister for keyboard notifications while not visible.
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
}
upvote
  flag
didnt work for me – u.gen
upvote
  flag
rect.origin.y=+currTextField.frame.origin.y working fine thank you – u.gen
upvote
  flag
Unfortunately it won't work in any mode other than Portrait. – Andrew Smith

Here is the hack solution I came up with for a specific layout. This solution is similar to Matt Gallagher solution in that is scrolls a section into view. I am still new to iPhone development, and am not familiar with how the layouts work. Thus, this hack.

My implementation needed to support scrolling when clicking in a field, and also scrolling when the user selects next on the keyboard.

I had a UIView with a height of 775. The controls are spread out basically in groups of 3 over a large space. I ended up with the following IB layout.

UIView -> UIScrollView -> [UI Components]

Here comes the hack

I set the UIScrollView height to 500 units larger then the actual layout (1250). I then created an array with the absolute positions I need to scroll to, and a simple function to get them based on the IB Tag number.

static NSInteger stepRange[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};

NSInteger getScrollPos(NSInteger i) {
    if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
        return 0 ;
    return stepRange[i] ;
}

Now all you need to do is use the following two lines of code in textFieldDidBeginEditing and textFieldShouldReturn (the latter one if you are creating a next field navigation)

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;

An example.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
    [self.scrollView setContentOffset:point animated:YES] ;
}


- (BOOL)textFieldShouldReturn:(UITextField *)textField {

    NSInteger nextTag = textField.tag + 1;
    UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];

    if (nextResponder) {
        [nextResponder becomeFirstResponder];
        CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
        [self.scrollView setContentOffset:point animated:YES] ;
    }
    else{
        [textField resignFirstResponder];
    }

    return YES ;
}

This method does not 'scroll back' as other methods do. This was not a requirement. Again this was for a fairly 'tall' UIView, and I did not have days to learn the internal layout engines.

upvote
  flag
This answer is some 7 years old!!!!!! It's a good example of "utterly out of place" material that hangs around on SO. – Fattie

I was also having a lot of issue with a UIScrollView composing of multiple UITextFields, of which, one or more of them would get obscured by the keyboard when they are being edited.

Here are some things to consider if your UIScrollView is not properly scrolling.

1) Ensure that your contentSize is greater than the UIScrollView frame size. The way to understand UIScrollViews is that the UIScrollView is like a viewing window on the content defined in the contentSize. So when in order for the UIScrollview to scroll anywhere, the contentSize must be greater than the UIScrollView. Else, there is no scrolling required as everything defined in the contentSize is already visible. BTW, default contentSize = CGSizeZero.

2) Now that you understand that the UIScrollView is really a window into your "content", the way to ensure that the keyboard is not obscuring your UIScrollView's viewing "window" would be to resize the UIScrollView so that when the keyboard is present, you have the UIScrollView window sized to just the original UIScrollView frame.size.height minus the height of the keyboard. This will ensure that your window is only that small viewable area.

3) Here's the catch: When I first implemented this I figured I would have to get the CGRect of the edited textfield and call UIScrollView's scrollRecToVisible method. I implemented the UITextFieldDelegate method textFieldDidBeginEditing with the call to the scrollRecToVisible method. This actually worked with a strange side effect that the scrolling would snap the UITextField into position. For the longest time I couldn't figure out what it was. Then I commented out the textFieldDidBeginEditing Delegate method and it all work!!(???). As it turned out, I believe the UIScrollView actually implicitly brings the currently edited UITextField into the viewable window implicitly. My implementation of the UITextFieldDelegate method and subsequent call to the scrollRecToVisible was redundant and was the cause of the strange side effect.

So here are the steps to properly scroll your UITextField in a UIScrollView into place when the keyboard appears.

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad 
{
    [super viewDidLoad];

    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:self.view.window];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification 
                                               object:self.view.window];
    keyboardIsShown = NO;
    //make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
    CGSize scrollContentSize = CGSizeMake(320, 345);
    self.scrollView.contentSize = scrollContentSize;
}

- (void)keyboardWillHide:(NSNotification *)n
{
    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;


    // resize the scrollview
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height += (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];

    keyboardIsShown = NO;
}

- (void)keyboardWillShow:(NSNotification *)n
{
    // This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown.  This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`.  If we were to resize the `UIScrollView` again, it would be disastrous.  NOTE: The keyboard notification will fire even when the keyboard is already shown.
    if (keyboardIsShown) {
        return;
    }

    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    // resize the noteView
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];
    keyboardIsShown = YES;
}
  1. Register for the keyboard notifications at viewDidLoad
  2. Unregister for the keyboard nofitications at viewDidUnload
  3. Ensure that the contentSize is set and greater than your UIScrollView at viewDidLoad
  4. Shrink the UIScrollView when the keyboard is present
  5. Revert back the UIScrollView when the keyboard goes away.
  6. Use an ivar to detect if the keyboard is already shown on the screen since the keyboard notifications are sent each time a UITextField is tabbed even if the keyboard is already present to avoid shrinking the UIScrollView when it's already shrunk

One thing to note is that the UIKeyboardWillShowNotification will fire even when the keyboard is already on the screen when you tab on another UITextField. I took care of this by using an ivar to avoid resizing the UIScrollView when the keyboard is already on the screen. Inadvertently resizing the UIScrollView when the keyboard is already there would be disastrous!

Hope this code saves some of you a lot of headache.

3 upvote
  flag
Great, but two problems: 1. UIKeyboardBoundsUserInfoKey is deprecated. 2. keyboardSize is in "screen coordinates", so your viewFrame calculations will fail if the frame is rotated or scaled. – Martin Wickman
20 upvote
  flag
@Martin Wickman - Use CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; instead of the deprecated UIKeyboardBoundsUserInfoKey – sottenad
upvote
  flag
Great answer but what should I do if I want to resize the view only if some of the controls are active. Let's say I have a textfield at the top of the view and one on the bottom, and I only want to resize the view for the textfield at the bottom. – gyozo kudor
upvote
  flag
This does not work as writ for iOS 5. Either there is something missing in the implementation description or the code, or something from the comments makes it work, but I could not get it to work properly in iOS 5. In fact, Apple's own docs have not been updated since iOS 3. – Philip Regan
1 upvote
  flag
HI, I did the same, but the text view only moves up when user starts typing? Is it the expected behavior or I am missing something? – user517491
upvote
  flag
@Shiun HI, I did the same, but the text view only moves up when user starts typing? Is it the expected behavior or I am missing something? – user517491
upvote
  flag
@Shiun you should also remove yourself as the observer in the dealloc method.. people often confuse the viewDidUnload as the opposite of the viewDidLoad... the viewDidUnload is only called when there is a memory warning.. so it might never be called, the dealloc, instead, will be called at some point for sure. – newton_guima
3 upvote
  flag
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size should be [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size . Great solution though! – j7nn7k
upvote
  flag
Like @djaqeel says, it would be great if the crolling whould happen as soon as the fields gets the focus, not when start typing. Secondly, scrolling back to the top or even the original position when the keyboard is hidden would be great. – Tim Büthe
upvote
  flag
Ok a couple more things here. From that userInfo dictionary you can get the animation duration and curve with the following keys: UIKeyboardAnimationDurationUserInfoKey and UIKeyboardAnimationCurveUserInfoKey. You should definitely use these instead of hard-coding!!! – Craig B
1 upvote
  flag
I like your solution but I think I can make it even simpler: don't bother with the Notification Observer stuff; instead call the right animation routines inside the appropriate delegate methods -- for UITextView they're textViewDidBeginEditing and textViewDidEndEditing. – AlexChaffee
upvote
  flag
@glenc What do you mean? How would I do that (could you supply sample code)? Because this works for me as well except for when the iPad is in landscape. – Mxyk
1 upvote
  flag
This is the correct answer. The other answer that's currently marked as correct has the keyboard size pinned to 80, which can very well change in iOS from version to version. This answer handles that situation appropriately. – Dan Loewenherz
upvote
  flag
keyboardIsShown property is required or your UIScrollview's contentInset bottom will grow larger when you click keyboard's globe key(change input). – tounaobun
upvote
  flag
This is not true for me "The keyboard notification will fire even when the keyboard is already shown." am I doing something wrong? I'm working with Xcode 6.1.1 on iOS 7 and 8. Autolayout disabled – David Cespedes
upvote
  flag
@DavidCespedes, which notification is firing? If its already visible then keyboardWillHide: should call. – Hemang
upvote
  flag
@hagile they say in the answer that "The keyboard notification will fire even when the keyboard is already shown." That's not true. It will only fire when it's going to be shown, but if it's already on the screen, it won't and shouldn't fire that keyboardWillShow again, as it is already shown. It is working like this since iOS 6 I think. Before it used to fire the notification no matter the keyboard was already shown. – David Cespedes
upvote
  flag
Pretty perfect. just i've followed you steps..Idea of Adjusting the scrollview frame is Awesome.. Even thought I'm using auto layout i've adjusted bottom space constraint for ScrollView :-) thanks a lot saved my day.. – Akshay
upvote
  flag
what is value of kTabBarHeight? – jayant rawat
upvote
  flag
Very important: use UIKeyboardFrameEndUserInfoKey instead of UIKeyboardFrameBeginUserInfoKey. Makes a difference when rotating the view. – CyberMoai

This document details a solution to this problem. Look at the source code under 'Moving Content That Is Located Under the Keyboard'. It's pretty straightforward.

EDIT: Noticed there's a wee glitch in the example. You will probably want to listen for UIKeyboardWillHideNotification instead of UIKeyboardDidHideNotification. Otherwise the scroll view behind of the keyboard will be clipped for the duration of the keyboard closing animation.

@user271753

To get your view back to original add:

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
   [textField resignFirstResponder];
   [self setViewMovedUp:NO];
   return YES;
}

Shiun said "As it turned out, I believe the UIScrollView actually implicitly brings the currently edited UITextField into the viewable window implicitly" This seems to be true for iOS 3.1.3, but not 3.2, 4.0, or 4.1. I had to add an explicit scrollRectToVisible in order to make the UITextField visible on iOS >= 3.2.

It's actually best just to use Apple's implementation, as provided in the docs. However, the code they provide is faulty. Replace the portion found in keyboardWasShown: just below the comments to the following:

NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);

CGPoint origin =  activeRect.origin;
origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, origin)) {
    CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
    [backScrollView setContentOffset:scrollPoint animated:YES];
}

The problems with Apple's code are these: (1) They always calculate if the point is within the view's frame, but it's a ScrollView, so it may already have scrolled and you need to account for that offset:

origin.y -= scrollView.contentOffset.y

(2) They shift the contentOffset by the height of the keyboard, but we want the opposite (we want to shift the contentOffset by the height that is visible on the screen, not what isn't):

activeField.frame.origin.y-(aRect.size.height)
upvote
  flag
Wouldn't a better solution be to adjust the size of the scrollview to have its height match the top of the keyboard? – zakdances
upvote
  flag
This doesn't work for me, my view scrolls down and not up it just completely hides behind my keyboard. – 8vius
upvote
  flag
@8vius Make sure you haven't inverted the origin of the view? Depending on what is defined as origin (0,0) it will change the logic. – DK_
1 upvote
  flag
In situations where the scroll view is not filling the screen, aRect should be set to the scroll view's frame – mblackwell8
upvote
  flag
@DK_ I followed Apple's implementation and changed the part you provided. However, it doesn't work for me. I can see that my hidden textField moves a very tiny bit up, but far from being visible. Any ideas where the issue might be? – makaed
upvote
  flag
@Makaed I'd double check your view frames. – DK_
upvote
  flag
@DK_ Seems good there. I have a few text fields in a generic scroll view (didn't subclass it, just created an outlet for it). That doesn't matter right? – makaed
2 upvote
  flag
Shouldn't you want the CGPoint origin = activeField.frame.origin + activeField.frame.size.height ?, because you want the whole textfield to be displayed and if it happens to have just some pixels visible then code won't enter the condition. – htafoya
upvote
  flag
Also this only works if the textfield is not at the bottom, because you are never changing the scrollview's position or size, then it won't be able to scroll through the bottom. – htafoya
1 upvote
  flag
This solution doesn't work in Landscape orientation — the text field flies off the top of the view port. iPad with iOS 7.1. – Andrew
upvote
  flag
This won't work if your TextField is embedded in some other views, as it's frame is based on it's superview not based on the scroll view. – hris.to
upvote
  flag
For point 2, it might be easiest to use: [self.scrollView scrollRectToVisible:activeField.frame animated:YES]; – Chris Nolet
4 upvote
  flag
For better iOS 8 support, I'd suggest using UIKeyboardFrameEndUserInfoKey instead of UIKeyboardFrameBeginUserInfoKey when getting the keyboard size, as this will pick up things such as custom keyboard changes and toggling predictive text on/off. – Endareth
1 upvote
  flag
@Egor: Your fix makes it work way better - but the last line must be inverse: self.scrollView.contentOffset = self.currentSVoffset; – Morten Holmgaard
upvote
  flag
@MortenHolmgaard Of course, you're right. That was a mistake while copy-pasting code from my project. – Egor
upvote
  flag
This doesn't work because UIKeyboardWillShowNotification will not get called when tapping the next button of a UITextField or when the keyboard is visible and you select another UITextField. It will just get called when the keyboard is going to be shown. – David Cespedes
upvote
  flag
Sept. 2015: I've implemented it with swift, it does correctly move the view up when begin editing a textview, however, when I scroll the ScrollView while the keyboard is still present, it resets to it's original, thus hiding the textview behind the keyboard again. Also, when I already scrolled down to the bottom a bit, it won't scroll up anymore when begin editing the Text view. I'll try below answer now: //allinonescript.com/a/17707278/2901207 – CularBytes

When UITextField is in a UITableViewCell scrolling should be setup automatically.

If it is not it is probably because of incorrect code/setup of the tableview.

For example when i reloaded my long table with one UITextField at the bottom as follows,

-(void) viewWillAppear:(BOOL)animated
{
   [self.tableview reloadData];
}

then my textfield at the bottom was obscured by the keyboard which appeared when I clicked inside the textfield.

To fix this I had to do this -

-(void) viewWillAppear:(BOOL)animated
{
    //add the following line to fix issue
    [super viewWillAppear:animated];
    [self.tableview reloadData];
}
upvote
  flag
I'm confused what this code is for? When the keyboard is shown, viewWillAppear is not called. And reloadData doesn't make obscured rows become visible. – Adam Johns

I've put together a universal, drop-in UIScrollView, UITableView and even UICollectionView subclass that takes care of moving all text fields within it out of the way of the keyboard.

When the keyboard is about to appear, the subclass will find the subview that's about to be edited, and adjust its frame and content offset to make sure that view is visible, with an animation to match the keyboard pop-up. When the keyboard disappears, it restores its prior size.

It should work with basically any setup, either a UITableView-based interface, or one consisting of views placed manually.

Here' tis: solution for moving text fields out of the way of the keyboard

upvote
  flag
This is it! This is the best, most efficient, and perfect solution! It also handles rotations properly for scroll views. If rotating be sure to autoresize vertically but do not anchor at the bottom. I added a UITextView to the scroll view in my case. Thanks bunches! – Christopher
upvote
  flag
Very nice work! Sure, I'm being lazy using your solution instead of the DIY one, but my boss is happier, so yeah! Even if someone does want to do themselves, I like your subclass approach, instead of adding code to each controller. I was shocked iOS didn't do this by default like Android did -- then again, I'm finding a lot of things lacking in iOS and MacOS :( – eselk
upvote
  flag
I spent the whole day yesterday trying to get one of the other answers to work (trying to avoid adding a whole library). Today I plug this in, except for minimal work, it works fine. By minimal work I mean renaming my scrollviews as TPKeyboardAvoidingScrollView – learner
upvote
  flag
Does weird things like my scrollview all fits in the screen, so it can't be scrolled. After opening and closing the keyboard, the content is now larger (looks like something invisible was added and not removed at the bottom of the page), and can be scrolled. – Almo

In textFieldDidBeginEditting and in textFieldDidEndEditing call the function [self animateTextField:textField up:YES] like so:

-(void)textFieldDidBeginEditing:(UITextField *)textField 
{ 
    [self animateTextField:textField up:YES]; 
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField:textField up:NO];
}

-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
    const int movementDistance = -130; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? movementDistance : -movementDistance); 

    [UIView beginAnimations: @"animateTextField" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

I hope this code will help you.

In Swift 2

func animateTextField(textField: UITextField, up: Bool) 
{
     let movementDistance:CGFloat = -130
     let movementDuration: Double = 0.3

     var movement:CGFloat = 0
     if up 
     {
         movement = movementDistance
     }
     else 
     {
         movement = -movementDistance
     }
     UIView.beginAnimations("animateTextField", context: nil)
     UIView.setAnimationBeginsFromCurrentState(true)
     UIView.setAnimationDuration(movementDuration)
     self.view.frame = CGRectOffset(self.view.frame, 0, movement)
     UIView.commitAnimations()
}


func textFieldDidBeginEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:true)
}

func textFieldDidEndEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:false)
}

SWIFT 3

 func animateTextField(textField: UITextField, up: Bool)
    {
        let movementDistance:CGFloat = -130
        let movementDuration: Double = 0.3

        var movement:CGFloat = 0
        if up
        {
            movement = movementDistance
        }
        else
        {
            movement = -movementDistance
        }
        UIView.beginAnimations("animateTextField", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration)
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }


    func textFieldDidBeginEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:true)
    }

    func textFieldDidEndEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:false)
    }
upvote
  flag
why not use [UIView animateWithDuration: animations:^{ }]; ? – André Cytryn
upvote
  flag
Just awesome man......just set your movement distance......and then you rocks.Well done – Nilesh Kumar
2 upvote
  flag
this works good, though const int movementDistance = -130; // tweak as needed needs to be changed to more flexible – Hammer
upvote
  flag
How can i make more flexible this line int movementDistance = -130;? – Fernando Santiago
upvote
  flag
@UserDev This works just fine on both iOS 7 and 8. The nav bar is not part of the view that is being animated in the code. – user3344977
7 upvote
  flag
Incredibly simple on small implementations. No mucking around with ScrollViews and Ambiguous auto-layout issues. – James Perih
upvote
  flag
This doesn't work anymore on iOS 9.1. Any workaround? – Gannicus
upvote
  flag
@Gannicus it works fine in 9.2 as well. make sure you have done the delegation connections. thats all – Im Batman
upvote
  flag
In fact, it works for multiple text fields also. Thanks – Muhammad Jabbar
upvote
  flag
I like the simplicity of this answer. When I switched to constraints (iOS >8), I also started to have problems. I expanded this answer in a new post @Gannicus to make it work again. – andreas
upvote
  flag
Using CGRectOffset will cause it to break when the size changes such is when switching predictive text on and off... The original location of the view should be saved and this should always be used as the base. Instead of incrementally adding to the views frame which in general is bad practice. Maybe this behaved differently in the past. – Andres Canella
upvote
  flag
Working perfect in iOS10, really simple and works like charm, thanks – BootMaker
upvote
  flag
For anyone using a storyboard and trying to make it work but can't, just make sure that self.view has leading, top and trailing constraints. Otherwise, it probably won't work. – Burak
4 upvote
  flag
Erm...you don´t use the textField parameter at all. Why then have it as a function parameter? Additionally, you could use the ternary operator also in Swift. Makes the code less talky. – stk
upvote
  flag
If the background color of the View is something other than black, make sure you set the color of the Window to match your view so the user doesn't see behind it. i.e. self.window.backgroundColor = [UIColor whiteColor]; – bvmobileapps
upvote
  flag
Needs _ in method params to match Delegate and quiet warning func textFieldDidBeginEditing(_ textField: UITextField) – Picci
upvote
  flag
Spending couple of hours looking for solution, finally solution that actually works! Thanks! – user30646
upvote
  flag
you saved my day ..it works like charm in xcode 8 – Mohammad Julfikar

It doesn't require a scroll view to be able to move the view frame. You can change the frame of a viewcontroller's view so that the entire view moves up just enough to put the firstresponder text field above the keyboard. When I ran into this problem I created a subclass of UIViewController that does this. It observes for the keyboard will appear notification and finds the first responder subview and (if needed) it animates the main view upward just enough so that the first responder is above the keyboard. When the keyboard hides, it animates the view back where it was.

To use this subclass make your custom view controller a subclass of GMKeyboardVC and it inherits this feature (just be sure if you implement viewWillAppear and viewWillDisappear they must call super). The class is on github.

upvote
  flag
What license? Some of your files there have an open source license and some don't. – jaime
upvote
  flag
Warning: this code is not friendly with ARC projects. – Almo
upvote
  flag
You just add the build option to specify that those are non-ARC files or welcome to convert it to ARC and submit a pull request. – progrmr

Been searching for a good tutorial for beginners on the subject, found the best tutorial here.

In the MIScrollView.h example at the bottom of the tutorial be sure to put a space at

@property (nonatomic, retain) id backgroundTapDelegate;

as you see.

upvote
  flag
Hi savagenoob, thanks for the link provided and welcome to stackoverflow. Please try and provide as much info as you can when answering (future) questions - simple links are a bit brittle. That said, if the answer is a link to a good tutorial that might be overlooked. – Maarten Bodewes

You need to add scrollview programatically with specific frame size. You have to add UIScrollViewDelegate in .h file. You have to enable scrollview for that you need to write following in viewDidLoad().

scrollview.scrollEnabled=YES;
scrollview.delegate=self;

scrollview.frame = CGRectMake(x,y,width,height);
//---set the content size of the scroll view--- 

[scrollview setContentSize:CGSizeMake(height,width)];

In this way you can add your x,y,width and height values. I think this will help you.

A much, much more elegant solution is to use a UIView subclass (though this isn't always appropriate) and recalculate all your subviews on a parent's frame change (and be smart: only recalculate them if the new frame size has changed, i.e. use CGRectEqualToRect to compare the new frame when you override setFrame and BEFORE you call [super setFrame:frame_]). The only catch to this is that the UIViewController you intend to use should probably listen to keyboard events (or, you could do it in the UIView itself, for handy encapsulation). But only the UIKeyboardWillShowNotification and UIKeyboardWillHideNotification. This is just so it will look smooth (if you wait for CG to call it, you will get a moment of choppiness).

This has the advantage of building a UIView subclass that does the right thing, anyway.

The naive implementation would be to override drawRect: (don't), a better one would be to just use layoutSubviews (and then in the UIViewController, or whatnot you can call [view setNeedsLayout] in a SINGLE method that is called for either show or hide).

This solution gets away from hardcoding a keyboard offset (which will change if they are not in split, etc) and also means that your view could be a subview of many other views and still respond properly.

Don't hardcode something like that unless there is no other solution. The OS gives you enough info, if you've done things right, that you just need to redraw intelligently (based on your new frame size). This is much cleaner and the way you should do things. (There may be an even better approach, though.)

Cheers.

Try this:

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:self.m_Sp_Contact])
    {
        [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
    }
}

Please follow these steps ,it might be helpful. Put one view then put your textfield on that view and detect the event by delegate when your keyboard is coming up,at that time instant animate the view up(You can assign some position for that view also),then your view would be going up to that position.Do the same thing for animating the view down.

Thanks

As per the docs, as of iOS 3.0, the UITableViewController class automatically resizes and repositions its table view when there is in-line editing of text fields. I think it's not sufficient to put the text field inside a UITableViewCell as some have indicated.

From the docs:

A table view controller supports inline editing of table view rows; if, for example, rows have embedded text fields in editing mode, it scrolls the row being edited above the virtual keyboard that is displayed.

upvote
  flag
I found the same comment. Yes, it is true. The strange thing is, that it is working in one UITabelViewController and in a second one not. But I could not find any differences in my implementation. – Morpheus78

There so many solutions, but I've spend some hours before it start works. So, I put this code here (just paste to the project, any modifications needn't):

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
    UITextField* activeField;
    UIScrollView *scrollView;
}
@end

- (void)viewDidLoad
{
    [super viewDidLoad];

    scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

    //scrool view must be under main view - swap it
    UIView* natView = self.view;
    [self setView:scrollView];
    [self.view addSubview:natView];

    CGSize scrollViewContentSize = self.view.frame.size;
    [scrollView setContentSize:scrollViewContentSize];

    [self registerForKeyboardNotifications];
}

- (void)viewDidUnload {
    activeField = nil;
    scrollView = nil;
    [self unregisterForKeyboardNotifications];
    [super viewDidUnload];
}

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShown:)
                                                 name:UIKeyboardWillShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];

}

-(void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

- (void)keyboardWillShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect frame = self.view.frame;
    frame.size.height -= kbSize.height;
    CGPoint fOrigin = activeField.frame.origin;
    fOrigin.y -= scrollView.contentOffset.y;
    fOrigin.y += activeField.frame.size.height;
    if (!CGRectContainsPoint(frame, fOrigin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
     [scrollView setContentOffset:CGPointZero animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    activeField = nil;
}

-(BOOL) textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}

P.S: I hope the code help somebody make desired effect quickly. (Xcode 4.5)

upvote
  flag
Hi Hotjard, i am getting EXE_BAD_ACCESS in the [self.view addSubview:natView]; – Bala

Lots of answers here, but this works and is much shorter than most:

- (void)textFieldDidBeginEditing:(UITextField *)sender
{
    UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView's controller
    const double dontHardcodeTheKeyboardHeight = 162;
    double textY = [sender convertPoint:CGPointMake(0, 0) toView:scrollView].y;
    if (textY - scrollView.contentOffset.y + sender.frame.size.height > self.view.frame.size.height - dontHardcodeTheKeyboardHeight)
        [scrollView setContentOffset:CGPointMake(0.0, textY - 10) animated:YES];
}

Just using TextFields:

1a) Using Interface Builder: Select All TextFields => Edit => Embed In => ScrollView

1b) Manually embed TextFields in UIScrollView called scrollView

2) Set UITextFieldDelegate

3) Set each textField.delegate = self; (or make connections in Interface Builder)

4) Copy / Paste:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y);
    [scrollView setContentOffset:scrollPoint animated:YES];
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [scrollView setContentOffset:CGPointZero animated:YES];
}
8 upvote
  flag
But it also moves up the view when textField is already visible. – TheTiger
1 upvote
  flag
Need to change CGPointMake(0, textField.frame.origin.y); to CGPointMake(0, textField.frame.origin.y + scrollView.contentInset.top); – Egor T
upvote
  flag
@Egor Even after your comment it doesn't work. Like "TheTiger" mentioned it moves up the view even after textfield is visible. – rak appdev

You can do by using textfield delegate methods also. Check below code. It's working for me when placed textfield on scroll view.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
     if(textField == answer)
    {   
         CGPoint cPoint = textField.frame.origin;
         [scrollView setContentOffset:CGPointMake(0, cPoint.y - 100) animated:YES];
    }
}

Note: You have to change cPoint.y - 100 value according to your view.

Here is a free library for keyboard handling Keyboard-Handling-in-iPhone-Applications. You need write just one line of code:

[AutoScroller addAutoScrollTo:scrollView];

This is awesome to handle keyboard in forms

upvote
  flag
Register to download? ..no thanks. Please host on github or similar. – quantumpotato
upvote
  flag
The interface looks nice though. – quantumpotato
upvote
  flag
not bad, but I have a problem with this library. It's a pitty that code is not on github. But anyway, thanks. – George

There are already a lot of answers, but still none of the solutions above had all the fancy positioning stuff required for a "perfect" bug-free, backwards compatible and flicker-free animation. (bug when animating frame/bounds and contentOffset together, different interface orientations, iPad split keyboard, ...)
Let me share my solution:
(assuming you have set up UIKeyboardWill(Show|Hide)Notification)

// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = [notification userInfo];

    CGRect keyboardFrameInWindow;
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];

    // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
    CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];

    CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
    UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);

    // this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    _scrollView.contentInset = newContentInsets;
    _scrollView.scrollIndicatorInsets = newContentInsets;

    /*
     * Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
     * that should be visible, e.g. a purchase button below an amount text field
     * it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
     */
    if (_focusedControl) {
        CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
        controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.

        CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y;
        CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;

        // this is the visible part of the scroll view that is not hidden by the keyboard
        CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;

        if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
            // scroll up until the control is in place
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);

            // make sure we don't set an impossible offset caused by the "nice visual offset"
            // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
            newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        } else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) {
            // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y = controlFrameInScrollView.origin.y;

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        }
    }

    [UIView commitAnimations];
}


// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = notification.userInfo;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    // undo all that keyboardWillShow-magic
    // the scroll view will adjust its contentOffset apropriately
    _scrollView.contentInset = UIEdgeInsetsZero;
    _scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;

    [UIView commitAnimations];
}
upvote
  flag
Great improvements of @Shiun answer. But after keyboard is gone, the view do not back in the 1st position. It's still a great work :) – Lucien
1 upvote
  flag
Thanks, this is the best solution for me in 2017. Note that you don't need to track the focusedControl yourself, you can determine that with UIApplication.shared.sendAction(...). Here's the Swift 3 version of your answer (minus willHide portion), with the sendAction implemented: gist.github.com/xaphod/7aab1302004f6e933593a11ad8f5a72d – xaphod
upvote
  flag
@xaphod in my case I needed to focus more controls - e.g. a button below an input field. but yeah that code is now 4 years old and may benefit from improvements. – Martin Ullrich

Please follow these steps.

1) Declare following variable in .h file.

  {      
         CGFloat animatedDistance;
  }

2) Declare following constants in .m file.

  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;

3) Use UITextField delegate to move up/down keyboard.

  -(void) textFieldDidBeginEditing:(UITextField *)textField
  { 
         if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
         {
               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)
               {
                     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
  {
       if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
       {
             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];
       }
 }
upvote
  flag
This answer was directly copied from cocoawithlove.com/2008/10/… – Koen

For Universal Solution, Here was my approach for implementing IQKeyboardManager.

enter image description here

Step1:- I Added global notifications of UITextField, UITextView, and UIKeyboard in a singleton class. I call it IQKeyboardManager.

Step2:- If found UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification or UITextViewTextDidBeginEditingNotification notifications, I try to get topMostViewController instance from the UIWindow.rootViewController hierarchy. In order to properly uncover UITextField/UITextView on it, topMostViewController.view's frame needs to be adjusted.

Step3:- I calculated expected move distance of topMostViewController.view with respect to first responded UITextField/UITextView.

Step4:- I moved topMostViewController.view.frame up/down according to the expected move distance.

Step5:- If found UIKeyboardWillHideNotification, UITextFieldTextDidEndEditingNotification or UITextViewTextDidEndEditingNotification notification, I again try to get topMostViewController instance from the UIWindow.rootViewController hierarchy.

Step6:- I calculated disturbed distance of topMostViewController.view which needs to be restored to it's original position.

Step7:- I restored topMostViewController.view.frame down according to the disturbed distance.

Step8:- I instantiated singleton IQKeyboardManager class instance on app load, so every UITextField/UITextView in the app will adjust automatically according to the expected move distance.

That's all IQKeyboardManager do for you with NO LINE OF CODE really!! only need to drag and drop related source file to project. IQKeyboardManager also support Device Orientation, Automatic UIToolbar Management, KeybkeyboardDistanceFromTextField and much more than you think.

upvote
  flag
Add IQKeyBoardManagerSwift directory to my project and don't work. Can't enable cuz its not recognize in AppDelegate... – user3722523
upvote
  flag
this feels like phishing the actual solution is not shown but instead we see a commercial to this guys GitHub account. – Brian

Just found this class:

https://github.com/OliverLetterer/SLScrollViewKeyboardSupport

And so far it works very well on iPhone, including animations & the correct offset.

To use it, simply add to viewDidLoad:

self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];
  • If the text field is not completely or partially hidden then we should not change anything.
  • We should calculate exact intersection area(keyboard's frame and textfield's frame) which is hidden and then we should change the view's frame.

  • Here i am giving a complete example .

    Declaring 3 varible

#define PADDING 10

@interface PKViewController ()
      @property (nonatomic, assign) CGRect originalViewFrame; //original view's frame
      @property (nonatomic, strong) UITextField *activeTextField; // current text field
      @property (nonatomic, assign) CGRect keyBoardRect; // covered area by keaboard
     @end

Store original frame

- (void)viewDidLoad {
    [super viewDidLoad];
    _originalViewFrame = self.view.frame;
}

Add your view controller as observer for keyboard notification

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}

Remove observer

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Store the area covered by the keyboard when it appears and set it to CGRectZero when it disappear

- (void)keyboardWasShown:(NSNotification *)notification{
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    _keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);
    [self moveTextFieldUP];

}
- (void) keyboardWillHide:(NSNotification *)notification{
    _keyBoardRect = CGRectZero;
    [self setDefaultFrame];
}

Store the active textfield

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    _activeTextField = textField;
//When keyboard is already present but the textfield is hidden. Case:When return key of  keyboard makes the next textfield as first responder
    if (!CGRectIsEmpty(_keyBoardRect)) { 
        [self moveTextFieldUP];
    }
    return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    [textField resignFirstResponder];
    return YES;
}

Now we should change the frame of the view

- (void)moveTextFieldUP{
    CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.origin.y, _activeTextField.frame.size.width, _activeTextField.frame.origin.y+_activeTextField.frame.size.height);
    if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {
        CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);
        CGFloat newY = _originalViewFrame.origin.y - intersectRect.size.height;
        CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;
        CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);
        [UIView animateWithDuration:0.3 animations:^{
            [self.view setFrame:newFrame];
        }];

        NSLog(@"Intersect");
    }
}
- (void)setDefaultFrame {
    [UIView animateWithDuration:0.3 animations:^{
        [self.view setFrame:_originalViewFrame];
    }];
}

I recently found myself in a similar scenario when working on a messaging app. I created a custom UIView that sticks to the top of the keyboard and does most of what you need automatically

MessageComposerView

http://www.thegameengine.org/wp-content/uploads/2013/11/message_composer_quad_1.jpg

The idea behind this project was to create something that functioned similar to the iMessage composition view AKA:

  • sticks to top of keyboard and moves to bottom of screen when keyboard dismissed
  • handles changes in text
  • handles rotations

In order to resize/reconfigure your UIScrollView you'll want to use the following optional delegate method:

- (void)messageComposerFrameDidChange:(CGRect)frame withAnimationDuration:(float)duration;

It will be called whenever the frame is changed (resized, repositioned, rotated) and will also supply the animation duration. You can use this information to resize your UIScrollView's frame and content insets as needed.

IF YOU ARE STILL STRUGGLING WITH THIS — READ MY POST

I have come up with a solution today. I've read numerous posts and "tutorials" about this issue and NONE of them works in every case (most of them are copy-pastes of each other). Even Apple's officially proposed "solution" doesn't work, and more, it totally doesn't work in landscape mode. Shame on Apple for not giving the devs means to beat such a common basic issue. Very unprofessional. Such an amazing framework (Cocoa) and such a nasty underrated issue.

Now, my solution: make UIScrollView your root view and then put everything in it. Then subclass your view controller from this KeyboardAwareController class (you may want to redefine scrollView and keyboardPadding methods):

// // KeyboardAwareController.h // Sociopathy // // Created by Admin on 13.01.14. // Copyright (c) 2014 kuchumovn. All rights reserved. //

#import <UIKit/UIKit.h>

@interface KeyboardAwareController : UIViewController <UITextFieldDelegate>

@end

// // KeyboardAwareController.m // Sociopathy // // Created by Admin on 13.01.14. // Copyright (c) 2014 kuchumovn. All rights reserved. //

#import "KeyboardAwareController.h"

@interface KeyboardAwareController ()

@end

@implementation KeyboardAwareController
{
    CGPoint scrollPositionBeforeKeyboardAdjustments;

    __weak UIScrollView* scrollView;

    UITextField* activeField;
}

- (id) initWithCoder: (NSCoder*) decoder
{
    if (self = [super initWithCoder:decoder])
    {
        scrollPositionBeforeKeyboardAdjustments = CGPointZero;
    }
    return self;
}

- (void) viewDidLoad
{
    [super viewDidLoad];
}

- (UIScrollView*) scrollView
{
    return (UIScrollView*) self.view;
}

- (CGFloat) keyboardPadding
{
    return 5;
}

- (void) registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardDidShow:)
                                                 name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void) deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardDidShowNotification
                                                  object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

- (void) viewWillAppear: (BOOL) animated
{
    [super viewWillAppear:animated];

    [self registerForKeyboardNotifications];
}

- (void) viewWillDisappear: (BOOL) animated
{
    [self deregisterFromKeyboardNotifications];

    [super viewWillDisappear:animated];
}

- (void) keyboardWillShow: (NSNotification*) notification
{
    //NSLog(@"keyboardWillShow");

    // force the animation from keyboardWillBeHidden: to end
    scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;

    scrollPositionBeforeKeyboardAdjustments = CGPointZero;
}

// warning: i have no idea why this thing works and what does every line of this code mean
// (but it works and there is no other solution on the internets whatsoever)
// P.S. Shame on Apple for missing such a basic functionality from SDK (and many other basic features we have to hack and mess around with for days and nights)

- (void) keyboardDidShow: (NSNotification*) notification
{
    //NSLog(@"keyboardDidShow");

    UIWindow* window = [[[UIApplication sharedApplication] windows]objectAtIndex:0];
    UIView* mainSubviewOfWindow = window.rootViewController.view;

    CGRect keyboardFrameIncorrect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect keyboardFrame = [mainSubviewOfWindow convertRect:keyboardFrameIncorrect fromView:window];
    CGSize keyboardSize = keyboardFrame.size;

    CGRect visibleFrame = CGRectMake(0, 0, 0, 0);
    visibleFrame.origin = self.scrollView.contentOffset;
    visibleFrame.size = self.scrollView.bounds.size;

    CGFloat paddedKeyboardHeight = keyboardSize.height + self.keyboardPadding;

    //NSLog(@"visibleFrame %@", NSStringFromCGRect(visibleFrame));

    visibleFrame.size.height -= paddedKeyboardHeight;

    //NSLog(@"visibleFrame after keyboard height %@", NSStringFromCGRect(visibleFrame));

    if (CGRectContainsPoint(visibleFrame, activeField.frame.origin))
        return;

    scrollPositionBeforeKeyboardAdjustments = scrollView.contentOffset;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height, 0);

    contentInsets = UIEdgeInsetsMake(0.0, 0.0, paddedKeyboardHeight, 0);

    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;

    CGSize scrollContentSize = self.scrollView.bounds.size;
    scrollContentSize.height += paddedKeyboardHeight;
    self.scrollView.contentSize = scrollContentSize;

    //NSLog(@"scrollView %@", NSStringFromCGRect(scrollView.frame));
    //NSLog(@"activeField %@", NSStringFromCGRect(activeField.frame));

    //[scrollView scrollRectToVisible:activeField.frame animated:YES];

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height);

    //NSLog(@"scrollPoint %@", NSStringFromCGPoint(scrollPoint));

    [self.scrollView setContentOffset:scrollPoint animated:YES];
}

- (void) keyboardWillBeHidden: (NSNotification*) notification
{
    //NSLog(@"keyboardWillBeHidden");

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    // this doesn't work when changing orientation while the keyboard is visible
    // because when keyboardDidShow: will be called right after this method the contentOffset will still be equal to the old value
    //[scrollView setContentOffset:scrollPositionBeforeKeyboardAdjustments animated:YES];

    [UIView animateWithDuration:.25 animations:^
    {
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;

        // replacement for setContentOffset:animated:
        self.scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;
    }];
}

- (void) textFieldDidBeginEditing: (UITextField*) textField
{
    activeField = textField;
}

- (void) textFieldDidEndEditing: (UITextField*) textField
{
    activeField = nil;
}
@end

If you have any questions, my project is hosted here on github: https://github.com/kuchumovn/sociopathy.ios

I also took a screenshot for better explanation: see the storyboard layout screenshot

2 upvote
  flag
It would be useful to have some feedback from people who down-voted this answer. – Zoltán

I didn't see this possibility here, so i'm adding it, since I tried the methods in the answers but hours later discovered there is a much easier way in XCode 5 in iOS6/7: Use NSLayoutConstraints.

See: Autolayout Constraint - Keyboard

Here is my code:

.m file:

// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
    NSLog(@"keyboardWillBeShown:");
    [self.PhoneNumberLabelOutlet setHidden:TRUE];
    CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
    for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
        thisConstraint.constant -= heightOfLabel;
    }

    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGFloat oldConstant = [self.SignInYConstraint constant];
    self.SignInYConstraint.constant = oldConstant + kbSize.height;
    [self.view setNeedsUpdateConstraints];

    NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:duration animations:^{
        [self.view layoutIfNeeded];
    }];

}

.h file:

#import <UIKit/UIKit.h>

@interface SignInViewController : UIViewController {

    UITextField* _activeField;
}




- (void)signInCallback:(NSObject*)object;


@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;

@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;

@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;

@property (weak, nonatomic) IBOutlet UIButton *SignInButton;

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;

@end

I found @DK_ to be the solution I started using. However, there is the assumption that the scrollView covers the entire view. That was not the case for me. I only wanted a scrollView in case the keyboard covered the lower textfield on my login screen. So my content view was the same size as my scroll view, which was smaller than the main view.

It also didn't account for landscapes, which is where I got into trouble to begin with. After playing around with it for several days, this is my keyboardWasShown: method.

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    // A lot of the inspiration for this code came from http:////allinonescript.com/a/4837510/594602
    CGFloat height = 0;
    NSDictionary* info = [aNotification userInfo];

    CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.

    CGRect scrollRect = scrollView.frame;
    CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);

    if (!CGRectIsNull(intersect))
    {
        height = intersect.size.height;
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // Figure out what the view rectangle is for the scrollView
    CGPoint contentOffset = scrollView.contentOffset;
    CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y);    // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
    visibleRect.size.height -= height;
    CGRect activeRect = activeField.frame;

    if (!CGRectContainsRect(visibleRect, activeRect))
    {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

I also had some difficulties getting to to work with auto layout. If I don't have the layouts done correctly, I don't get the scrolling I expected. One thing that made life much easier was to place all of the items that were to be scrolling into a single view, and placed that as the only item in the scroll view. I called that single view the "content view".

I think the key part was that the content view had a set width and height. This allowed the scroll view to know exactly how much content it had to deal with. This goes a little backwards from usual layouts. Normally the views are trying to take as much room as possible. With the contents of a scroll view, you are trying to get the view to confine itself as much as possible. The content view allows you to put a stop to that. So I gave mine a height of 248, and used the standard screen width of 320 as my width.

The layouts that eventually worked for me were these:

  • Scroll View to super view: Basically I gave constraints to the top, left and right.
    • Horizontal Space - View - Scroll View (0)
    • Vertical Space - View - Scroll View (0)
    • Horizontal Space - Scroll View - View (0)
  • Scroll View height: I set the scroll view with a constant height. I don't know if this was truly necessary, but it got the bounds of the scroll view itself.
    • Height - (248) - Scroll View
  • The content view to the scroll view: I gave constants to all sides, the top, left, bottom and right.
    • Vertical Space - View - Scroll View (0)
    • Vertical Space - Scroll View - View (0)
    • Horizontal Space - View - Scroll View (0)
    • Horizontal Space - Scroll View - View (0)
  • The dimensions of the content view.
    • Height - (248) - View
    • Width - (320) - View

in (BOOL)textFieldShouldBeginEditing:(UITextField *)textField

if (textField.frame.origin.y > self.view.frame.size.height - 216)
    {
        if (screenHeight>500)
            scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);
        else
            scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);
        CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
    [scrollView setScrollEnabled:YES];

when resigning keyBoard you need to write bellow code

scrollView.contentSize = CGSizeMake(0.0, 640);
CGPoint scrollPoint = CGPointMake(0.0,0.0);
[scrollView setContentOffset:scrollPoint animated:YES]; 

here is a UITextfield (and other similar fields) category that i made that will make the textfield avoid the keyboard, you should be able to drop this in your view controller as is and it should work. It moves the entire screen up so the current textfield is above the keyboard with animations

#import "UIView+avoidKeyboard.h"
#import "AppDelegate.h"

@implementation UIView (avoidKeyboard)

- (void) becomeFirstResponder {

if(self.isFirstResponder)
    return;

[super becomeFirstResponder];

if ([self isKindOfClass:[UISearchBar class]] ||
    [self isKindOfClass:[UITextField class]] ||
    [self isKindOfClass:[UITextView class]])
{
    AppDelegate *appDelegate    = [UIApplication sharedApplication].delegate;

    CGRect screenBounds         = appDelegate.window.frame;

    CGFloat keyboardHeight;
    CGFloat keyboardY;
    CGFloat viewsLowestY;
    CGPoint origin              = [self.superview convertPoint:self.frame.origin toView:appDelegate.window]; //get this views origin in terms of the main screens bounds

    if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the origin instead of the y
        keyboardHeight          = 216;
        keyboardY               = screenBounds.size.height  - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved up
        viewsLowestY            = origin.y + self.frame.size.height; //find the lowest point of this view
    }
    else {
        keyboardHeight          = 162;
        keyboardY               = screenBounds.size.width  - keyboardHeight;
        viewsLowestY            = origin.x + self.frame.size.height;
    }

    CGFloat difference          = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding

    if (difference > 0){ //move screen up if there is an overlap

        [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{

            CGRect frame = appDelegate.window.frame;

            if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){
                frame.origin.y -= difference;
            }
            else {
                frame.origin.x -= difference;
            }
            appDelegate.window.frame = frame;
        }
        completion:nil];
    }
}
}

//look at appDelegate to see when the keyboard is hidden

@end

In your appDelegate add this function

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions

...

- (void)keyboardHides:(NSNotification *)notification
{
    [UIView animateWithDuration:0.3 animations:^{
        [window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];
    } completion:nil];
}
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {

  [self slideUp];
   return YES;
}

-(BOOL) textFieldShouldEndEditing:(UITextField *)textField {

    [self slideDown];
   return YES;
}

#pragma mark - Slide Up and Down animation

- (void) slideUp {
    [UIView beginAnimations:nil context:nil];
    layoutView.frame = CGRectMake(0.0, -70.0, layoutView.frame.size.width, layoutView.frame.size.height);

    [UIView commitAnimations];
}


- (void) slideDown {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDelay: 0.01]; 
    layoutView.frame = CGRectMake(0.0, 0.0, layoutView.frame.size.width, layoutView.frame.size.height);
    [UIView commitAnimations];
}
upvote
  flag
Here what is layoutView ?? – RaviJSS

Note: this answer assumes your textField is in a scrollView.

I prefer to deal with this using scrollContentInset and scrollContentOffset instead of messing with the frames of my view.

First let's listen for the keyboard notifications

//call this from viewWillAppear
-(void)addKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
    [[NSNotificationCenter default
    Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Next step is to keep a property that represents the current first responder (UITextfield/ UITextVIew that currently has the keyboard).

We use the delegate methods to set this property. If you're using another component, you will need something similar.

Note that for textfield we set it in didBeginEditing and for textView in shouldBeginEditing. This is because textViewDidBeginEditing gets called after UIKeyboardWillShowNotification for some reason.

-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
    self.currentFirstResponder = textView;
    return YES;
}

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.currentFirstResponder = textField;
}

Finally, here's the magic

- (void)keyboardWillShow:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];


    /*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
    if(self.currentFirstResponder){

        //keyboard origin in currentFirstResponderFrame
        CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil];

        float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);

        //only scroll the scrollview if keyboard overlays the first responder
        if(spaceBetweenFirstResponderAndKeyboard>0){
            //if i call setContentOffset:animate:YES it behaves differently, not sure why
            [UIView animateWithDuration:0.25 animations:^{
                [self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
            }];
        }
    }

    //set bottom inset to the keyboard height so you can still scroll the whole content

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;

}

- (void)keyboardWillHide:(NSNotification*)aNotification{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;
}

There are many answers available telling the approach. I took the same approach but the implementation isn't good.

Here is the base Idea . I made modifications to keyboardWasShown method.

{
// Obtain keyboard Info
NSDictionary* info = [notification userInfo];
CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

// Obtain ScrollView Info w.r.t. top View
CGRect scrollViewRect = [self.view convertRect:self.scrollView.frame fromView:nil];

// Depending upon your screen Ui, Scroll View's bottom edge might be at some offset from screen's bottom
// Calculate the exact offset
int scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.origin.y + scrollViewRect.size.height);
int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;


// We may also need to consider the Insets if already present with ScrollView. Let's keep it simple for now
// But we should store these, so that we can restore the Insets when Keyboard is gone
// origInsets = self.scrollView.contentInset;

// Set the new Insets for ScrollView
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, heightToBeAdjusted, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;

// Visible frame (not overlapped by Keyboard)
CGRect visibleFrame = self.view.frame;
visibleFrame.size.height -= keyboardRect.size.height;

// Get the Rect for Textfield w.r.t self.view
CGRect activeFieldFrame = self.activeField.frame;
activeFieldFrame = [self.view convertRect:activeFieldFrame fromView:self.scrollView];

// Check if the TextField is Visible or not
if (!CGRectContainsRect(visibleFrame, activeFieldFrame) ) {
    // Scroll to make it visible but for scrolling use the activeField frame w.r.t. to scroll View
    [self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}

}

And add this method to initialize the activeField

- (IBAction)textFieldDidBeginEditing:(UITextField *)sender
{
self.activeField = sender;
}
upvote
  flag
How can you return to the original state? I've tried UIEdgeInsets contentInsets = UIEdgeInsetsZero; self.scrollView.contentInset = contentInsets; self.scrollView.scrollIndicatorInsets = contentInsets; like in the example but with no success. Edit: I solved it with this: [self.scrollView setContentOffset:CGPointMake(0, 0)]; is that ok? – Axort

https://github.com/michaeltyson/TPKeyboardAvoiding download this file and add custom class as this in your table view it will manage all things for you don't need to do any thing. it has many option you can check it out for other also ,this is all you need to avoid keyboard

Here is my version using autolayout :

The idea is just to embed your view containing textfields / text view in an UIScrollView, set a constraint from the bottom to it's superview, make an outlet and update it's constant according to keyboard height using notifications. This is based on Apple example here, and Apple technical note on UIScrollView using AutoLayout here.

1) Embed your View V in a UIScrollView S : If you already set your constants and subviews, you can copy/paste your view and subviews in the ViewController's view, then embed it using Editor -> embed menu, and finally delete the copied views.)

2) Set the following constraints :

  • S to top layout guide : 0
  • S to bottom layout guide : 0
  • S leading to superview : 0
  • S trailing to superview : 0

  • V top space to superview : 0

  • V bottom space to superview : 0
  • V trailing space to superview : 0
  • V leading space to superview : 0

  • V equal width to S

  • Latest bottom V subview to superview : 20

3) Create an outlet from the latest constraint to your view controller

4) Use the following code :

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpaceToContentView;

// ...

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    // ...

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Handle keyboard

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    self.bottomSpaceToContentView.constant = kBottomMargin + kbSize.height;
    [self.view layoutIfNeeded];
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.bottomSpaceToContentView.constant = kBottomMargin;
    [self.view layoutIfNeeded];
}

And tadaaaaa, it works !

Easiest solution found

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self animateTextField: textField up: YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField: textField up: NO];
}

- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
    const int movementDistance = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? -movementDistance : movementDistance);

    [UIView beginAnimations: @"anim" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}
upvote
  flag
The Screen moves up even if it is not at the bottom. ie, if the text field is on the top it moves out of the screen. How to control that case? – MELWIN
upvote
  flag
@MELWIN Just add after this line: int movement = (up ? -movementDistance : movementDistance); if (textField.frame.origin.y < self.view.frame.size.height - keyboard.height) { movementDistance = 0 } Please not that the keyboard variable is the CGRect of the keyboard that pops up which you get by doing: let keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]!.CGRe‌​ctValue())! – ToothyRel

This is the solution using Swift.

import UIKit

class ExampleViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var scrollView: UIScrollView!

    @IBOutlet var textField1: UITextField!
    @IBOutlet var textField2: UITextField!
    @IBOutlet var textField3: UITextField!
    @IBOutlet var textField4: UITextField!
    @IBOutlet var textField5: UITextField!

    var activeTextField: UITextField!

    // MARK: - View
    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField1.delegate = self
        self.textField2.delegate = self
        self.textField3.delegate = self
        self.textField4.delegate = self
        self.textField5.delegate = self
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.registerForKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.unregisterFromKeyboardNotifications()
    }

    // MARK: - Keyboard

    // Call this method somewhere in your view controller setup code.
    func registerForKeyboardNotifications() {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterFromKeyboardNotifications () {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
        center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    // Called when the UIKeyboardDidShowNotification is sent.
    func keyboardWasShown (notification: NSNotification) {
        let info : NSDictionary = notification.userInfo!
        let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size

        let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;

        // If active text field is hidden by keyboard, scroll it so it's visible
        // Your app might not need or want this behavior.
        var aRect = self.view.frame
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
            self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
        }
    }

    // Called when the UIKeyboardWillHideNotification is sent
    func keyboardWillBeHidden (notification: NSNotification) {
        let contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // MARK: -  Text Field

    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }

}
upvote
  flag
Correct answer,but I am having nil problem when using both TextField and TextView. Any Help? – Thiha Aung
upvote
  flag
@Thiha Aung, Are your IBOutlet variables in your source code connected to the IB? – Homam
upvote
  flag
Yeah they are connected as well.Just having that error when using UITextView at that line : if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) { – Thiha Aung
upvote
  flag
Means self.activeTextField is nil – Thiha Aung

first of all, u better design ur page as no need to scroll ur view. if u have many textfields, u still dont have to use scrollview, it just make things complicated. u can just add a container uiview on the top of controller's original view then you put those textfields on this view. when keyboard shows of disappears, just move this container view with an animation.

A simple solution extending the UIViewController

https://github.com/damienromito/VisibleFormViewController

enter image description here

I use Swift and auto layout (but can't comment on the previous Swift answer); here's how I do it without a scroll view:

I layout my form in IB with vertical constraints between the fields to separate them. I add a vertical constraint from the topmost field to the container view, and create an outlet to that (topSpaceForFormConstraint in the code below). All that's needed is to update this constraint, which I do in an animation block for a nice soft motion. The height check is optional of course, in this case I needed to do it just for the smallest screen size.

This can be called using any of the usual textFieldDidBeginEditing or keyboardWillShow methods.

func setFormHeight(top: CGFloat)
{
    let height = UIScreen.mainScreen().bounds.size.height

    // restore text input fields for iPhone 4/4s
    if (height < 568) {
        UIView.animateWithDuration(0.2, delay: 0.0, options: nil, animations: {
            self.topSpaceForFormConstraint.constant = top
            self.view.layoutIfNeeded()
            }, completion: nil)
    }

}

I've found this to be the best solution, follow the code below:

Attach the below to your Vertical Space - Bottom Layout Guide - TextField constraint.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;

Second add observers for keyboard notifications.

- (void)observeKeyboard {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

Add this to your viewDidLoad

[self observeKeyboard]; 

Finally the methods that handles keyboard changes.

- (void)keyboardWillShow:(NSNotification *)notification {
//THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.
kbHeight = 0;
height = 0;
self.textViewBottomConst.constant = height;
self.btnViewBottomConst.constant = height;

    NSDictionary *info = [notification userInfo];
    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardFrame = [kbFrame CGRectValue];

    CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    int kbHeight = finalKeyboardFrame.size.height;

    int height = kbHeight + self.textViewBottomConst.constant;

    self.textViewBottomConst.constant = height;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    self.textViewBottomConst.constant = 10;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

This worked for me:

func setupKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWasShown(aNotification:NSNotification) {
    let info = aNotification.userInfo
    let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
    let kbSize = infoNSValue.CGRectValue().size
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
    var rect : CGRect = self.view.frame
    rect.size.height -= kbSize.height

    self.view.frame = rect
    UIView.commitAnimations()
}

func keyboardWillBeHidden(aNotification:NSNotification) {
    let info = aNotification.userInfo
    let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
    let kbSize = infoNSValue.CGRectValue().size
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
    var rect : CGRect = self.view.frame
    rect.size.height += kbSize.height
    self.view.frame = rect
    UIView.commitAnimations()
}

For Swift Programmers :

This will do everything for you, just put these in your view controller class and implement the UITextFieldDelegate to your view controller & set the textField's delegate to self

textField.delegate = self // Setting delegate of your UITextField to self

Implement the delegate callback methods:

func textFieldDidBeginEditing(textField: UITextField) {
    animateViewMoving(true, moveValue: 100)
}

func textFieldDidEndEditing(textField: UITextField) {
    animateViewMoving(false, moveValue: 100)
}

// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}
1 upvote
  flag
SwiftLint didn't like self.view.frame = CGRectOffset(self.view.frame, 0, movement) so I changed that line to self.view.frame.offsetInPlace(dx: 0, dy: movement) – levibostian
upvote
  flag
Swift 4 change self.view.frame = CGRectOffset(self.view.frame, 0, movement) to self.view.frame.offsetBy(dx: 0, dy: movement) – Asinox

I wrap everything in one class. Just call these lines of code when your viewcontroller is loaded:

- (void)viewDidLoad {
    [super viewDidLoad];
    KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];
    [injectView injectToView:self.view withRootView:self.view];
}

Here is link of sample project:
https://github.com/caohuuloc/KeyboardInsetScrollView

upvote
  flag
What kind of license have your code? – Beto

try this short trick...

 - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        [self animateTextField: textField up: YES];
    }

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        [self animateTextField: textField up: NO];
    }

    - (void) animateTextField: (UITextField*) textField up: (BOOL) up
    {
        const int movementDistance = textField.frame.origin.y / 2; // tweak as needed
        const float movementDuration = 0.3f; // tweak as needed

        int movement = (up ? -movementDistance : movementDistance);

        [UIView beginAnimations: @"anim" context: nil];
        [UIView setAnimationBeginsFromCurrentState: YES];
        [UIView setAnimationDuration: movementDuration];
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
        [UIView commitAnimations];
    }

Happy coding :)....

Simple solution and with latest animation api. Changing the origin.y by 215, you can customize it to whichever value works for you.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    if (self.view.frame.origin.y >= 0) {

        [UIView animateWithDuration:0.5 animations:^{
           self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-215, self.view.frame.size.width, self.view.frame.size.height);
       }];
   }
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    if (self.view.frame.origin.y < 0) {
        [UIView animateWithDuration:0.5 animations:^{
           self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+215, self.view.frame.size.width, self.view.frame.size.height);
        }];

    }
}

Here I found the simplest solution to handle keypad.

You need to just copy-paste below sample code and change your textfield or any view which you want to move up.

Step-1

Just copy-paste below two method in your controller

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Step-2

register & deregister Keypad Notifications in viewWillAppear and viewWillDisappear methods respectively.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self registerForKeyboardNotifications];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self deregisterFromKeyboardNotifications];
    [super viewWillDisappear:animated];
}

Step-3

Here comes the soul part, Just replace your textfield, and change height how much you want to move upside.

- (void)keyboardWasShown:(NSNotification *)notification
{
    NSDictionary* info = [notification userInfo];
    CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    //you need replace your textfield instance here
    CGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin;
    CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;

    CGRect visibleRect = self.view.frame;
    visibleRect.size.height -= currentKeyboardSize.height;

    if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
    {
        //you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below

        CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height  + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
        [self.scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification *)notification
{
    [self.scrollView setContentOffset:CGPointZero animated:YES];
}

Reference: well, Please appreciate this guy, who shared this beautiful code snip, clean solution.

Hope this would be surly helpful someone out there.

upvote
  flag
I don't think this is the best. Ithink @Dheeraj V.S. is right: It can be done easily & automatically if that textfield is in a table's cell (even when the table.scrollable = NO). NOTE that: the position and size of the table must be reasonable. e.g: - if the y position of table is 100 counted from the view's bottom, then the 300 height keyboard will overlap the whole table. - if table's height = 10, and the textfield in it must be scrolled up 100 when keyboard appears in order to be visible, then that textfield will be out of the table's bound. – samthui7
upvote
  flag
@samthui7 Dheeraj answer only works if you're using a TableViewController , not just a tableview. It makes it a constraint that sometimes isn't suitable. – Ben G
Please add this lines in textfield delegate method to scroll up in iPad.    

- (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        activeTextfield = textField;
    CGPoint pt;
        CGRect rc = [textField bounds];
        rc = [textField convertRect:rc toView:scrlView];
        pt = rc.origin;
        pt.x = 0;
        pt.y -= 100;

        [scrlView setContentOffset:pt animated:YES];

        scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.origin.y+button.frame.size.height + 8 + 370);
    }

Use this third party you don't need to write even one line

https://github.com/hackiftekhar/IQKeyboardManager

download project and drag and drop IQKeyboardManager in your project. If you find any issue please read README document.

Guys really its remove headache to manage keyboard ..

Thanks and best of luck!

It can be done easily & automatically if that textfield is in a table's cell (even when the table.scrollable = NO).

  • NOTE that: the position and size of the table must be reasonable. e.g:
    • if the y position of table is 100 counted from the view's bottom, then the 300 height keyboard will overlap the whole table.
    • if table's height = 10, and the textfield in it must be scrolled up 100 when keyboard appears in order to be visible, then that textfield will be out of the table's bound.

Very lightweight solution could be using KeyboardAnimator.

project got the sample implementation, documentation is still in progress...

Appropriate usage :: It's have a specific implementation for UITextField & UITextView

Limitation:: It's fully on objective-c, swift version will be available soon.

Swift 2.0:

Add a UIScrollView and add textFields on the top of it. Make storyboard references to VC.

@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var scrollView: UIScrollView!

Add these methods : UITextFieldDelegate & UIScrollViewDelegate.

//MARK:- TEXTFIELD METHODS
    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if(username.returnKeyType == UIReturnKeyType.Default) {
            password.becomeFirstResponder()
        }
        textField.resignFirstResponder()
        return true
    }
    func textFieldDidBeginEditing(textField: UITextField) {

        dispatch_async(dispatch_get_main_queue()) {

            let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/4)
            self.scrollView!.setContentOffset(scrollPoint, animated: true);
        }
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool {

        dispatch_async(dispatch_get_main_queue()) {
          UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
        }
        return true
    }
    override func touchesBegan(touches: Set<UITouch>,
        withEvent event: UIEvent?) {
            self.view.endEditing(true)
    }
    func scrollViewWillBeginDragging(scrollView: UIScrollView) {
        self.scrollView.scrollEnabled =  true

        dispatch_async(dispatch_get_main_queue()) {
            UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)

            })
        }
    }

This will work Perfectly.The scroll view atmatically adjust by textfield position.i am sure you will feel good

static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.25;
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;
@interface LoginVC ()
{
  CGFloat animatedDistance;
   CGRect viewFrameKey;
}

 //In ViewDidLoad
   viewFrameKey=self.view.frame;



- (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
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrameKey];
[UIView commitAnimations];
}

I would like to extend the answer of @sumanthkodi.

As some people have stated, his approach doesn't work in newer implementations, because the UIView fails to move when you are using constraints.

I edited the code as follows (and ported to Swift 2.0) and hope that it helps some people:


1) Reference the vertical constraint of the view you would like to move up:

@IBOutlet var viewConstraint: NSLayoutConstraint!

Make sure you reference this var in your storyboard with the constraint.

2) Add the delegate and implement the listeners. This is the same implementation as before:

class YourViewController: UIViewController, UITextFieldDelegate {

    ...

    func textFieldDidBeginEditing(textField: UITextField) {
        animateTextField(textField, up: true)
    }

    func textFieldDidEndEditing(textField: UITextField) {
        animateTextField(textField, up: false)
    }

    ...

}

3) Add your animation method animateTextField to YourViewController class. Set the temporary constraint value as needed.

func animateTextField(textfield: UITextField, up: Bool) {

    let originalConstraint = 50
    let temporaryConstraint = 0
    let movementDuration = 0.3

    let constraint = CGFloat(up ? temporaryConstraint : originalConstraint)

    containerViewConstraint.constant = constraint
    UIView.animateWithDuration(movementDuration) {
        self.view.layoutIfNeeded()
    }

}

I think that the best approach is to use protocol-oriented programming if you are using Swift.

First of all you must create a KeyboardCapable protocol, that gives to any UIViewController conforming it the ability to register and unregister keyboard observers:

import Foundation
import UIKit

protocol KeyboardCapable: KeyboardAnimatable {
    func keyboardWillShow(notification: NSNotification)
    func keyboardWillHide(notification: NSNotification)
}

extension KeyboardCapable where Self: UIViewController {
    func registerKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }
}

You've notice the extraneous KeyboardAnimatable keyword on the above piece of code. It's just the name of the next protocol we need to create:

import Foundation
import UIKit

protocol KeyboardAnimatable {

}

extension KeyboardAnimatable where Self: UIViewController {
    func performKeyboardShowFullViewAnimation(withKeyboardHeight height: CGFloat, andDuration duration: NSTimeInterval) {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            self.view.frame = CGRectMake(view.frame.origin.x, -height, view.bounds.width, view.bounds.height)
            }, completion: nil)
    }

    func performKeyboardHideFullViewAnimation(withDuration duration: NSTimeInterval) {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            self.view.frame = CGRectMake(view.frame.origin.x, 0.0, view.bounds.width, view.bounds.height)
            }, completion: nil)
    }
}

This KeyboardAnimatable protocol, gives all UIViewController conforming it two methods that will animate the whole view up and down, respectively.

Okay so if KeyboardCapable conforms to KeyboardAnimatable, all UIViewController conforming to KeyboardCapable, also conforms to KeyboardAnimatable. That's cool.

Let's see a UIViewController conforming KeyboardCapable, and reacting to keyboard events:

import Foundation
import UIKit

class TransferConfirmViewController: UIViewController, KeyboardCapable {
    //MARK: - LIFE CYCLE       
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        registerKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        unregisterKeyboardNotifications()
    }

    //MARK: - NOTIFICATIONS
    //MARK: Keyboard
    func keyboardWillShow(notification: NSNotification) {
        let keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
        let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        performKeyboardShowFullViewAnimation(withKeyboardHeight: keyboardHeight, andDuration: animationDuration)
    }

    func keyboardWillHide(notification: NSNotification) {
        let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        performKeyboardHideFullViewAnimation(withDuration: animationDuration)
    }
}

Now your UIViewController will respond to keyboard events and will animate in consequence.

Note: If you want a custom animation instead of push or pull the view, you must define custom methods on KeyboardAnimatable protocol or perform them on KeyboardCapable functions. It's up to you.

This can be simply achieved with below lines of code using constraints

- (void)viewDidAppear:(BOOL)animated {
    [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];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    [self adjustTextViewByKeyboardState:YES keyboardInfo:[notification userInfo]];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    [self adjustTextViewByKeyboardState:NO keyboardInfo:[notification userInfo]];
}

- (void)viewDidDisappear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super viewDidDisappear:animated];
}

- (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {
    CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat height = keyboardFrame.size.height;
    self.constraintToAdjust.constant = height;        UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
    UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;
    if (animationCurve == UIViewAnimationCurveEaseIn) {
        animationOptions |= UIViewAnimationOptionCurveEaseIn;
    }
    else if (animationCurve == UIViewAnimationCurveEaseInOut) {
        animationOptions |= UIViewAnimationOptionCurveEaseInOut;
    }
    else if (animationCurve == UIViewAnimationCurveEaseOut) {
        animationOptions |= UIViewAnimationOptionCurveEaseOut;
    }
    else if (animationCurve == UIViewAnimationCurveLinear) {
        animationOptions |= UIViewAnimationOptionCurveLinear;
    }
    [UIView animateWithDuration:[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:animationOptions animations:^{
        [self.view layoutIfNeeded];
    }                completion:nil];
}

This is offset calculation independent from device. Gets the overlapped height between keyboard and textfield:

func keyboardShown(notification: NSNotification) {
    let info  = notification.userInfo!
    let value: AnyObject = info[UIKeyboardFrameEndUserInfoKey]!

    let rawFrame = value.CGRectValue
    let keyboardFrame = view.convertRect(rawFrame, fromView: nil)

    let screenHeight = UIScreen.mainScreen().bounds.size.height;
    let Ylimit = screenHeight - keyboardFrame.size.height
    let textboxOriginInSuperview:CGPoint = self.view.convertPoint(CGPointZero, fromCoordinateSpace: lastTextField!)

    self.keyboardHeight = (textboxOriginInSuperview.y+self.lastTextField!.frame.size.height) - Ylimit

    if(self.keyboardHeight>0){
        self.animateViewMoving(true, moveValue: keyboardHeight!)
    }else{
        keyboardHeight=0
    }
}

keyBoardHeight is the offset.

It is very simple just put following code in your class and customise if you needed .

-(void)textFieldDidBeginEditing:(UITextField *)textField {
     //Show Keyboard
     self.view.frame = CGRectMake(self.view.frame.origin.x,
                              self.view.frame.origin.y-50,
                              self.view.frame.size.width,
                              self.view.frame.size.height);   
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
     // Hide keyboard
     self.view.frame = CGRectMake(self.view.frame.origin.x,
                              self.view.frame.origin.y+50,
                              self.view.frame.size.width,
                              self.view.frame.size.height); 
}

Though this thread has got enough answers, I would like to suggest a much simpler yet generalised way just like apple does by takes keypads's height into consideration which is greatly helpful when we are using custom toolbar on top of keyboard. though apple's approach here has got few issues.

Here is my approach (Slightly modified apple's way) -

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}
  1. Download TPKeyBoardAvoiding From this link: https://github.com/michaeltyson/TPKeyboardAvoiding.
  2. Expand the zipped folder and find TPKeyboardAvoiding folder.
  3. Select all .h and .m files and drop it to your project.Make sure copy items if needed is ticked.
  4. Drag and drop a UIScrollView to StoryBoard and associate with TPKeyboardAvoidingScrollView.
  5. Now you can add UI elements on the top of the scroll view. Note that this class detect the UI elements touches even after dragging the scrollView.

On Your ViewController:

@IBOutlet weak var usernameTextfield: UITextField!
@IBOutlet weak var passwordTextfield: UITextField!
@IBOutlet weak var loginScrollView: UIScrollView!


override func viewWillAppear(animated: Bool) {
        loginScrollView.scrollEnabled =  false
    }

Add TextField Delegates.

//MARK:- TEXTFIELD METHODS
func textFieldShouldReturn(textField: UITextField) -> Bool
{
    if (usernameTextfield.resignFirstResponder())
    {
        passwordTextfield.becomeFirstResponder()
    }
    textField.resignFirstResponder();
    loginScrollView!.setContentOffset(CGPoint.zero, animated: true);
    loginScrollView.scrollEnabled =  false
    return true
}
func textFieldDidBeginEditing(textField: UITextField)
{
    loginScrollView.scrollEnabled =  true

    if (textField.tag  == 1 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
    {
        let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.4);
        loginScrollView!.setContentOffset(scrollPoint, animated: true);

    }
    else if (textField.tag  == 2 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
    {
        let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.0);
        loginScrollView!.setContentOffset(scrollPoint, animated: true);
    }
}
func textFieldDidEndEditing(textField: UITextField)
{
    loginScrollView!.setContentOffset(CGPointZero,animated: true);
}

This piece of code will calculate how much need to move up based on the keyboard height and how deep the text field as gone. Remember to add delegate and inherit UITextFieldDelegate at your header.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [_tbxUsername resignFirstResponder];
    [_tbxPassword resignFirstResponder];
}

- (void)textFieldDidBeginEditing:(UITextField *) textField
{
    [self animateTextField:textField up:YES];
}

- (void)textFieldDidEndEditing:(UITextField *) textField
{
    [self animateTextField:textField up:NO];
}

- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
    int animatedDistance;
    int moveUpValue = textField.frame.origin.y+ textField.frame.size.height;
    UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationPortrait ||
        orientation == UIInterfaceOrientationPortraitUpsideDown)
    {

        animatedDistance = 236-(460-moveUpValue-5);
    }
    else
    {
        animatedDistance = 182-(320-moveUpValue-5);
    }

    if(animatedDistance>0)
    {
        const int movementDistance = animatedDistance;
        const float movementDuration = 0.3f;
        int movement = (up ? -movementDistance : movementDistance);
        [UIView beginAnimations: nil context: nil];
        [UIView setAnimationBeginsFromCurrentState: YES];
        [UIView setAnimationDuration: movementDuration];
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
        [UIView commitAnimations];
    }
}

Delegate to add at ViewDidLoad

_tbxUsername.delegate = self;
_tbxPassword.delegate = self;

A much simpler yet generalised way just like apple does by takes keypads's height into consideration which is greatly helpful when we are using custom toolbar on top of keyboard. though apple's approach here has got few issues.

Here is my approach (Slightly modified apple's way) -

// UIKeyboardDidShowNotification
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

// UIKeyboardWillHideNotification
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

Set Scrollview in view

  - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
     CGPoint point;
    if(textField == txtEmail){
      // -90 is for my you can change as per your postion
      point = CGPointMake(0, textField.frame.origin.y - 90);
    }
    else if (textField == txtContact){
      point = CGPointMake(0, textField.frame.origin.y - 90);
    }
      [scrollV setContentOffset:point animated:YES];
    }

its simple:-

In TextFieldDidBeginEditing:-

self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-150, self.view.frame.size.width, self.view.frame.size.height);

In TextFieldShouldEndEditing:-

self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+150, self.view.frame.size.width, self.view.frame.size.height);

In iOS moving keyboard up and taking back for textfields in app is bit confusing and need to implement few methods for same. also you need to make delegate to textfield and take care of it. Code for it will repeat in every class where the text fields exist.

I prefer to use this Github control.

IQKeyboard

In which We do not need to do anything. -- just drag drop control to your project and build. -- It will do everything for your app.

Thanks

May be this will be useful.

1 upvote
  flag
this is exactly what i am looking for . thanks . i ll implement it right away . – Moxarth

Try IQKeyboard library.

This will automatically move the text field's up.

i had an issue with reseting to default main view while changing the text field or editing it's content (for example phone textfield and adding '-' sign, and view goes back covering textfields) i finnaly overcome this by using auto layout and changing constraints constant, not frame size or position in notification delegates functions, like this:

P.S. I'm not using scrollview just simple move view up, but it should work similar

func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
    if !keyboardIsShown{
        self.infoViewTopConstraint.constant -= keyboardSize.height
        self.infoViewBottomConstraint.constant += keyboardSize.height
        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()
        keyboardIsShown = true
    }
}

func keyboardWillHide(notification: NSNotification) {
if keyboardIsShown {
    self.infoViewTopConstraint.constant += keyboardSize.height
    self.infoViewBottomConstraint.constant -= keyboardSize.height
    self.view.setNeedsLayout()
    self.view.layoutIfNeeded()
    keyboardIsShown = false
}

Try this it's working perfectly:

if Firstnametxt.text == "" || Passwordtxt.text == "" || emailtxt.text == ""
    {
        if Firstnametxt.text == ""
        {
            Firstnametxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            Firstnametxt.becomeFirstResponder()
        }
        else if Passwordtxt.text == ""
        {
            Passwordtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            Passwordtxt.becomeFirstResponder()
        }
        else if emailtxt.text == ""

        {

            emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            emailtxt.becomeFirstResponder()
        }

    }
    else
    {
        let isValidEmail:Bool = self.isValidEmail(emailtxt.text!)
        if isValidEmail == true
        {
                        }
        else
        {
            emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            emailtxt.becomeFirstResponder()

        }

    }
upvote
  flag
It's better to include some context/explanation with code as this makes the answer more useful for the OP and for future readers. – EJoshuaS

You don't have to rely on custom code creation for moving any view up when keyboard will appears You can simply user library IQKeyboardManagerSwift same available for Objective-C code also

i am late a little bit. You should add scrollView on your viewController.

You must be implement below 2 method.

TextField delegate method.

    - (void)textFieldDidBeginEditing:(UIView *)textField {
    [self scrollViewForTextField:reEnterPINTextField];
}

And then call the below methon in delegate method.

 - (void)scrollViewForTextField:(UIView *)textField {
    NSInteger keyboardHeight = KEYBOARD_HEIGHT;

    if ([textField UITextField.class]) {
        keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
    } 

    CGRect screenFrame = [UIScreen mainScreen].bounds;
    CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
    aRect.size.height -= keyboardHeight;
    CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
    CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);

    if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
        CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
        [contentSlidingView setContentOffset:scrollPoint animated:YES];
    }
}

Swift 3.0 version of Apples keyboard management code is here: FloatingTF used in the code below is a Material design based textfield in iOS.

import UIKit
class SignupViewController: UIViewController, UITextFieldDelegate {

    //MARK: - IBOutlet:
@IBOutlet weak var emailTF: FloatingTF!
@IBOutlet weak var passwordTF: FloatingTF!
@IBOutlet weak var dobTF: FloatingTF!

@IBOutlet weak var scrollView: UIScrollView!

//MARK: - Variable:
var activeTextField: UITextField!

//MARK: - ViewController Lifecycle:
override func viewDidLoad() {
    super.viewDidLoad()        
    emailTF.delegate = self
    passwordTF.delegate = self
    dobTF.delegate = self 
}
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    registerKeyboardNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

   deRegisterKeyboardNotifications()
}

//MARK: - Keyboard notification observer Methods
fileprivate func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
fileprivate func deRegisterKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: self.view.window)
}
func keyboardWillShow(notification: NSNotification) {

    let info: NSDictionary = notification.userInfo! as NSDictionary
    let value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue
    let keyboardSize: CGSize = value.cgRectValue.size
    let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your app might not need or want this behavior.
    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize.height
    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
    if (!aRect.contains(activeTextFieldOrigin!)) {
        scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
    }    }

func keyboardWillHide(notification: NSNotification) {
    let contentInsets: UIEdgeInsets = .zero
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

//MARK: - UITextField Delegate Methods
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if textField == emailTF {
        passwordTF.becomeFirstResponder()
    }
    else if textField == passwordTF {
        dobTF.becomeFirstResponder()
    }
    else {
        self.view.endEditing(true)
    }
    return true
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    activeTextField = textField
    scrollView.isScrollEnabled = true
}

func textFieldDidEndEditing(_ textField: UITextField) {
    activeTextField = nil
    scrollView.isScrollEnabled = false
}
}

Just add this to you pod file -> pod 'IQKeyboardManager'

Thats it, handles all of keyboard, and scrollviews and everything!

You dont need to code anything, could not find a better solution!

It has an extension, which handles textfields display, screen shifting, next and previous arrows if there are multiple text fields.

It also has a custom done button, which can be removed.

Link -> https://github.com/hackiftekhar/IQKeyboardManager

For Swift Developer, using Swift 3, here is the repo https://github.com/jamesrochabrun/KeyboardWillShow

import UIKit

class ViewController: UIViewController {

    //1 Create a view that will hold your TEXTFIELD
    let textField: UITextField = {
        let tf = UITextField()
        tf.translatesAutoresizingMaskIntoConstraints = false
        tf.layer.borderColor = UIColor.darkGray.cgColor
        tf.layer.borderWidth = 3.0
        return tf
    }()
    //2 global variable that will hold the bottom constraint on changes
    var textfieldBottomAnchor: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        //3 add the view to your controller
        view.addSubview(textField)
        textField.heightAnchor.constraint(equalToConstant: 80).isActive = true
        textField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
        textField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        textfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        textfieldBottomAnchor?.isActive = true

        setUpKeyBoardObservers()
    }
    //4 Use NSnotificationCenter to monitor the keyboard updates
    func setUpKeyBoardObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    //5 toggle the bottom layout global variable based on the keyboard's height
    func handleKeyboardWillShow(notification: NSNotification) {

        let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect
        if let keyboardFrame = keyboardFrame {
            textfieldBottomAnchor?.constant = -keyboardFrame.height
        }
        let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
        if let keyboardDuration = keyboardDuration {
            UIView.animate(withDuration: keyboardDuration, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }

    func handleKeyboardWillHide(notification: NSNotification) {

        textfieldBottomAnchor?.constant = 0
        let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
        if let keyboardDuration = keyboardDuration {
            UIView.animate(withDuration: keyboardDuration, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }
    //6 remove the observers
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        NotificationCenter.default.removeObserver(self)
    }
}

Simple Solution For Scrollview with TextFields is below, No need any Constraints or active textfield etc...

 override func viewWillAppear(_ animated: Bool){
        super.viewWillAppear(animated)
        registerForKeyboardNotifications();


    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        deregisterFromKeyboardNotifications();
    }
    //MARK:- KEYBOARD DELEGATE METHODS
        func registerForKeyboardNotifications(){
            //Adding notifies on keyboard appearing
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        }
        func deregisterFromKeyboardNotifications(){
            //Removing notifies on keyboard appearing
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        }
        func keyboardWasShown(notification: NSNotification){

            var info = notification.userInfo!
            let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
            var contentInset:UIEdgeInsets = self.scrRegister.contentInset
            contentInset.bottom = (keyboardSize?.height)!
            scrRegister.contentInset = contentInset


        }
        func keyboardWillBeHidden(notification: NSNotification)
        {
            var contentInset:UIEdgeInsets = self.scrRegister.contentInset
            contentInset.bottom = 0
            scrRegister.contentInset = contentInset

        }

I know this is too late but I wanted to share with the future visitors especially my way of doing it. Many good methods were shared but I didn't like how the UI becomes totally bad. There's a simple method which involves two parts:-

  1. Add the TextField and, whatever you want it to be floating above the keyboard while editing, to a view so they become children of the view. And then it will be easy to maintain the look and not to affect the UI badly.
  2. Use the great tool CGAffineTransform(TranslationX: x, TranslationY: y) to move the created view above the keyboard.

I know it seems very simple but it is really effective and neat. enter image description here

You can use this simple Git repository: https://github.com/hackiftekhar/IQKeyboardManager

This is a library that manages all the moving of fields automatically.

According to their readme, the integration is super easy:

without needing you to enter any code and no additional setup required. To use IQKeyboardManager you simply need to add source files to your project

Although,this is very good control, in some cases it causes conflict, like in the view controllers with scroll view. It sometimes changes the content size. Still, you can go for it, and try it as per your requirement maybe you could do what I missed.

Not the answer you're looking for? Browse other questions tagged or ask your own question.