73

I have a UIView, it is not inside UIScrollView. I would like to move up my View when the keyboard appears. Before I tried to use this solution: How can I make a UITextField move up when the keyboard is present?.

It was working fine. But after inserting the data in the textfields, it takes me to another view, and when I get back to this page, its just jumping, and I couldn't see my text fields. Is there any better solution for this problem?

Donald Duck
  • 6,488
  • 18
  • 59
  • 79
Anatoliy Gatt
  • 2,481
  • 3
  • 24
  • 42

18 Answers18

89
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[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];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

#pragma mark - keyboard movements
- (void)keyboardWillShow:(NSNotification *)notification
{
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    [UIView animateWithDuration:0.3 animations:^{
        CGRect f = self.view.frame;
        f.origin.y = -keyboardSize.height;
        self.view.frame = f;
    }];
}

-(void)keyboardWillHide:(NSNotification *)notification
{
    [UIView animateWithDuration:0.3 animations:^{
        CGRect f = self.view.frame;
        f.origin.y = 0.0f;
        self.view.frame = f;
    }];
}
theDuncs
  • 4,211
  • 4
  • 35
  • 58
  • what is setFrameOriginY.Please can you explain this – Akhtar Feb 12 '14 at 07:42
  • @Austin_ak Apologies. I've replaced that with the real code now. – theDuncs Feb 12 '14 at 08:51
  • 1
    This worked well for me, and I combined it with this answer [link](http://stackoverflow.com/a/6938494/4495850) to get the keyboard to hide when the user clicks anywhere else on the screen. – Richard Oct 29 '15 at 14:09
  • 3
    It doesn't work if user changes to another keyboard with different height (like emoji one). To fix it, in keyboardWillShow you should use: CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; – Daniel Albert Jun 25 '16 at 19:00
  • 2
    thumb up. this solution is so much simpler than what Apple could offer. Apple solution couldn't fix my issue, but yours just snap. Thanks. – TPG Mar 09 '17 at 03:08
  • 1
    This work. But problem it also push the top view become invisible. How to move down the top view? – user2872856 Mar 13 '17 at 05:15
  • 1
    This is a very decent solution but what I would suggest is instead of moving the view that much up, check if the textfield is hidden first then move it by the hidden amount. – Georgio Sayegh May 01 '17 at 23:15
  • How do you check if the textfield is hidden behind the keyboard before moving the view up – Kirandeep Kaur Jan 23 '19 at 09:26
80

Use the following code in order to show and hide the keyboard

//Declare a delegate, assign your textField to the delegate and then include these methods

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
    return YES;
}


- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];

    [self.view endEditing:YES];
    return YES;
}


- (void)keyboardDidShow:(NSNotification *)notification
{
    // Assign new frame to your view 
    [self.view setFrame:CGRectMake(0,-110,320,460)]; //here taken -110 for example i.e. your view will be scrolled to -110. change its value according to your requirement.

}

-(void)keyboardDidHide:(NSNotification *)notification
{
    [self.view setFrame:CGRectMake(0,0,320,460)];
}
Niall Kiddle
  • 1,319
  • 1
  • 12
  • 30
Ani Shroff
  • 1,155
  • 8
  • 10
  • 48
    The size of the keyboard should be determined from the infoDictionary that is passed with the keyboard notification, and this should be used to calculate an appropriate yOffset rather than statically defining one. – isaac Jul 01 '12 at 13:57
  • 9
    this doesn't handle keyboard change notifications properly which means it does not account for when a user switches between keyboard languages and that changes the height of the keyboard (in the Japanese kanji keyboard hit the emoji button for an example). – Jehiah Nov 04 '12 at 17:16
  • Thanks for the solution @Ani Shroff . The upward movement is not smooth, it is more of a discrete movement. can you help regarding this. – Muhammad Irfan Mar 05 '14 at 14:03
  • 2
    I think there is no need of these notification you can simply call keyboardDidShow in textFieldShouldBeginEditing and keyboardDidHide in textFieldShouldEndEditing – AndroidGeek Oct 25 '14 at 10:48
  • This is the most easiest and efficient way to achieve this , use this link http://stackoverflow.com/questions/7952762/xcode-ios5-move-uiview-up-when-keyboard-appears/26237038#26237038 – Kishore Suthar May 15 '15 at 06:45
  • 13
    Is it me or this approach has a major problem. You are subscribing to the notification everytime you start or end editing in yout text field. The subscriptions should be done once when your layout is loaded. – Nuno Gonçalves Sep 16 '15 at 08:50
  • The observer for keyboard notifications should be added only once at the beginning in `viewDidLoad` or similar methods. Also, it should be removed if no longer necessary according to apple guidelines. Use the information available in the notification to get height of keyboard, animation curves, animation duration etc. This should avoid the glitch. – GoGreen Apr 05 '16 at 11:34
  • this works fine . but you should use this -- > [self.view setFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)]; in keyboardDidHide: . then this code could be use full in all device sizes . – Moxarth Jun 29 '17 at 12:48
  • and if i am having n number of text fields , lets guess i have signup page to fill up . so that time top text field should not move up , middle text field should move up little bit and last text field should move up to the mark that user can see it . so that time , what would be the code modification ? – Moxarth Jun 29 '17 at 12:59
  • This is pretty outdated and anyone looking for to do this should explore the answers that use the animation keys rather than hardcoding any values – JAB Mar 02 '18 at 02:50
  • You really should not hardcode the frame of the keyboard. It varies (think iPad). Use UIKeyboardFrameBeginUserInfoKey and friends to find out the location the keyboard is or will be. Don't forget to convert coordinates since they are given in the window coordinate system. – toto Mar 23 '18 at 09:03
37

I wrote a little category on UIView that manages temporarily scrolling things around without needing to wrap the whole thing into a UIScrollView. My use of the verb "scroll" here is perhaps not ideal, because it might make you think there's a scroll view involved, and there's not--we're just animating the position of a UIView (or UIView subclass).

There are a bunch of magic numbers embedded in this that are appropriate to my form and layout that might not be appropriate to yours, so I encourage tweaking this to fit your specific needs.

UIView+FormScroll.h:

#import <Foundation/Foundation.h>

@interface UIView (FormScroll) 

-(void)scrollToY:(float)y;
-(void)scrollToView:(UIView *)view;
-(void)scrollElement:(UIView *)view toPoint:(float)y;

@end

UIView+FormScroll.m:

#import "UIView+FormScroll.h"


@implementation UIView (FormScroll)


-(void)scrollToY:(float)y
{

    [UIView beginAnimations:@"registerScroll" context:NULL];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationDuration:0.4];
    self.transform = CGAffineTransformMakeTranslation(0, y);
    [UIView commitAnimations];

}

-(void)scrollToView:(UIView *)view
{
    CGRect theFrame = view.frame;
    float y = theFrame.origin.y - 15;
    y -= (y/1.7);
    [self scrollToY:-y];
}


-(void)scrollElement:(UIView *)view toPoint:(float)y
{
    CGRect theFrame = view.frame;
    float orig_y = theFrame.origin.y;
    float diff = y - orig_y;
    if (diff < 0) {
        [self scrollToY:diff];
    }
    else {
        [self scrollToY:0];
    }

}

@end

Import that into your UIViewController, and then you can do

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self.view scrollToView:textField];
}

-(void) textFieldDidEndEditing:(UITextField *)textField
{
    [self.view scrollToY:0];
    [textField resignFirstResponder];
}

...or whatever. That category gives you three pretty good ways to adjust the position of a view.

Rishil Patel
  • 1,938
  • 3
  • 11
  • 28
Dan Ray
  • 21,345
  • 6
  • 61
  • 86
  • 4
    Determine the appropriate yOffset to pass to this category method based on the size of keyboard that is passed in the keyboardWillAppear NSNotification's infoDictionary. – isaac Jul 01 '12 at 13:59
  • 2
    @isaac - Absolutely. One of SEVERAL ways that code could be improved. – Dan Ray Jul 02 '12 at 14:03
31

Bind a view to keyboard is also an option (see GIF at the bottom of the answer)

Swift 4

Use an extension: (Wasn't fully tested)

extension UIView{
    func bindToKeyboard(){
        NotificationCenter.default.addObserver(self, selector: #selector(UIView.keyboardWillChange(notification:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
    }

    func unbindToKeyboard(){
        NotificationCenter.default.removeObserver(self, name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
    }
    @objc
    func keyboardWillChange(notification: Notification) {
        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.frame.origin.y+=deltaY

        },completion: nil)

    }
}

Swift 2 + 3

Use an extension:

extension UIView{
    func bindToKeyboard(){
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIView.keyboardWillChange(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil)
    }


    func keyboardWillChange(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
        let deltaY = targetFrame.origin.y - curFrame.origin.y


        UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
                self.frame.origin.y+=deltaY

        },completion: nil)

    }  
}

Usage:

// view did load...
textField.bindToKeyboard()

...

// view unload
textField.unbindToKeyboard()

result:
enter image description here

important
Don't forget to remove the observer when view is unloading

Daniel Krom
  • 8,637
  • 3
  • 36
  • 39
14

I found theDuncs answer very useful and below you can find my own (refactored) version:


Main Changes

  1. Now getting the keyboard size dynamically, rather than hard coding values
  2. Extracted the UIView Animation out into it's own method to prevent duplicate code
  3. Allowed duration to be passed into the method, rather than being hard coded

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

- (void)viewWillDisappear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    float newVerticalPosition = -keyboardSize.height;

    [self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f];
}


- (void)keyboardWillHide:(NSNotification *)notification {
    [self moveFrameToVerticalPosition:0.0f forDuration:0.3f];
}


- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration {
    CGRect frame = self.view.frame;
    frame.origin.y = position;

    [UIView animateWithDuration:duration animations:^{
        self.view.frame = frame;
    }];
}
Jamie
  • 859
  • 1
  • 7
  • 17
  • frame.origin.y = frame.origin.y - keyboardSize.height; or the keyboard will shoot outside the screen. – Alex Aug 28 '16 at 05:36
  • 1
    Exactly what I was looking for, except if you press the "dictation" button, then the view will never be raised again because you are using the `UIKeyboardFrameBeginUserInfoKey` instead of `UIKeyboardFrameEndUserInfoKey`. You should edit that, otherwise perfect! – damjandd Dec 21 '17 at 20:23
  • I have revised my answer to include @damjandd's suggestion - thanks! – Jamie May 20 '19 at 19:35
  • After changing self.view.frame you also need [self.view layoutSubviews]. This fixes issues with safe margins on iphone X if the @view contains tableTable. – Cynichniy Bandera Jan 11 '20 at 09:09
9

Based on Daniel Krom's solution. This is version in swift 3.0. Works great with AutoLayout, and moves whole view when keyboard appears.

extension UIView {

    func bindToKeyboard(){
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
    }

    func unbindFromKeyboard(){
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
    }

    @objc
    func keyboardWillChange(notification: NSNotification) {

        guard let userInfo = notification.userInfo else { return }

        let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.frame.origin.y += deltaY
        })
    }  
}

How to use it: Add bindToKeyboard function in viewDidLoad like:

override func viewDidLoad() {
    super.viewDidLoad()

    view.bindToKeyboard()
}

And add unbindFromKeyboard function in deinit:

deinit {
    view.unbindFromKeyboard()
}
Axel
  • 768
  • 5
  • 18
8

Swift 5

Updated version of answer by Daniel Krom above:

extension UIView {

    func bindToKeyboard() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(UIView.keyboardWillChange(notification:)),
            name: UIResponder.keyboardWillChangeFrameNotification,
            object: nil
        )
    }

    func unbindToKeyboard() {
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillChangeFrameNotification,
            object: nil
        )
    }

    @objc func keyboardWillChange(notification: Notification) {
        let duration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIView.KeyframeAnimationOptions(rawValue: curve), animations: {
            self.frame.origin.y += deltaY
        })
    }

}
Chris Chute
  • 2,039
  • 22
  • 16
5

For all the issue related to KeyBoard just use IQKeyBoardManager it's helpful. https://github.com/hackiftekhar/IQKeyboardManager.

Nikunj
  • 274
  • 3
  • 15
5

try this one:-

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


[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector (keyboardDidHide:)
                                                 name: UIKeyboardDidHideNotification object:nil];

-(void) keyboardDidShow: (NSNotification *)notif
    {
        CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height+[self getTableView].tableFooterView.frame.size.height, 0.0);

        [self getTableView].contentInset = contentInsets;
        [self getTableView].scrollIndicatorInsets = contentInsets;

        CGRect rect = self.frame; rect.size.height -= keyboardSize.height;
        if (!CGRectContainsPoint(rect, self.frame.origin))
        {
            CGPoint scrollPoint = CGPointMake(0.0, self.frame.origin.y - (keyboardSize.height - self.frame.size.height));
            [[self getTableView] setContentOffset:scrollPoint animated:YES];
        }
    }

-(void) keyboardDidHide: (NSNotification *)notif
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    [self getTableView].contentInset = contentInsets;
    [self getTableView].scrollIndicatorInsets = contentInsets;
}
3

Based on theDunc's answer but written in Swift with Autolayout.

@IBOutlet weak var bottomConstraint: NSLayoutConstraint! // connect the bottom of the view you want to move to the bottom layout guide

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    NSNotificationCenter.defaultCenter().addObserver(self,
                                                     selector: #selector(ConversationViewController.keyboardWillShow(_:)),
                                                     name: UIKeyboardWillShowNotification,
                                                     object: nil)

    NSNotificationCenter.defaultCenter().addObserver(self,
                                                     selector: #selector(ConversationViewController.keyboardWillHide(_:)),
                                                     name: UIKeyboardWillHideNotification,
                                                     object: nil)
}

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    super.viewWillDisappear(animated)
}

// MARK: - Keyboard events

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo,
        keyboardFrame = userInfo[UIKeyboardFrameBeginUserInfoKey]
    {
        let keyboardSize = keyboardFrame.CGRectValue().size
        self.bottomConstraint.constant = keyboardSize.height
        UIView.animateWithDuration(0.3) {
            self.view.layoutIfNeeded()
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    self.bottomConstraint.constant = 0
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}
Community
  • 1
  • 1
SeanR
  • 7,053
  • 5
  • 24
  • 38
2

I have implemented a custom controller that dynamically calculates the size of the keyboard, scrolling textFields when it appears and disappears, even during rotation of the device. Works with all iOS devices. Just simply inherit the controller to have what you need. You can find it with all the instructions at the following link: https://github.com/mikthebig/ios-textfield-scroll

mikthebig
  • 93
  • 1
  • 6
  • Just opened a pull request for your awesome solution, so it can also support UITextView type input fields, and not just UITextField: https://github.com/mikthebig/ios-textfield-scroll/pulls – Shiprack Nov 09 '13 at 21:15
2

Simple solution without adding observer notification

-(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)textFieldDidEndEditing:(UITextField *)sender
{
     if  (self.view.frame.origin.y >= 0)
        {
            [self setViewMovedUp:NO];
        }
}

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

Where

#define kOFFSET_FOR_KEYBOARD 80.0
AndroidGeek
  • 30,803
  • 14
  • 212
  • 262
  • 3
    Do not use this code - there is no set kOFFSET_FOR_KEYBOARD valid for all languages, devices and orientations. Take your keyboard height and appearance animation duration from UIKeyboardWillShowNotification and UIKeyboardWillHideNotification. – Adam Eberbach Feb 03 '15 at 01:04
1

Here you go. I have used this code with UIView, though. You should be able to make those adjustments for scrollview.

    func addKeyboardNotifications() {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillShow(notification:)),
                                               name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillHide(notification:)),
                                               name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    func keyboardWillShow(notification: NSNotification) {

        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
// if using constraints            
// bottomViewBottomSpaceConstraint.constant = keyboardSize.height
self.view.frame.origin.y -= keyboardSize.height
            UIView.animate(withDuration: duration) {
                self.view.layoutIfNeeded()
            }
        }
    }
    func keyboardWillHide(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
//if using constraint
//        bottomViewBottomSpaceConstraint.constant = 0
self.view.frame.origin.y = 0
        UIView.animate(withDuration: duration) {
            self.view.layoutIfNeeded()
        }
    }

Don't forget to remove notifications at right place.

func removeKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Cesare
  • 8,326
  • 14
  • 64
  • 116
Mohammad Sadiq
  • 4,041
  • 25
  • 25
1

Swift 4

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)

@objc func keyboardWillChange(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.YourView.frame.origin.y+=deltaY
        },completion: nil)
    }
ZAFAR007
  • 2,545
  • 1
  • 26
  • 40
1

Just in case someone is looking for solution in Swift, throw this in your code:

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

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: .UIKeyboardWillHide, object: nil)
}

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

    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}


@objc func keyboardWillShow(notification: Notification) {
    if let userInfo = notification.userInfo {
        if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            UIView.animate(withDuration: 0.3) {
                var alteredFrame = self.view.frame
                alteredFrame.origin.y = -keyboardSize.height
                self.view.frame = alteredFrame
            }
        }
    }
}

@objc func keyboardWillHide(notification: Notification) {
    UIView.animate(withDuration: 0.3) {
        var alteredFrame = self.view.frame
        alteredFrame.origin.y = 0.0
        self.view.frame = alteredFrame
    }
}
badhanganesh
  • 3,211
  • 2
  • 17
  • 34
0

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.
Rishil Patel
  • 1,938
  • 3
  • 11
  • 28
samthui7
  • 873
  • 2
  • 12
  • 11
0

Declare a delegate, assign your text field to the delegate and then include these methods.

Assuming you have a login form with email and password text fields, this code will fit perfectly:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [self.emailTextField resignFirstResponder];
    [self.passwordTextField resignFirstResponder];

}

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

    if (self.emailTextField == textField) {
        [self.passwordTextField becomeFirstResponder];
    } else {
        [self.emailTextField resignFirstResponder];
        [self.passwordTextField resignFirstResponder];
    }
    return NO;
}
- (void)viewWillAppear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

#pragma mark - keyboard movements
- (void)keyboardWillShow:(NSNotification *)notification
{
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    [UIView animateWithDuration:0.3 animations:^{
        CGRect f = self.view.frame;
        f.origin.y = -0.5f * keyboardSize.height;
        self.view.frame = f;
    }];
}

-(void)keyboardWillHide:(NSNotification *)notification
{
    [UIView animateWithDuration:0.3 animations:^{
        CGRect f = self.view.frame;
        f.origin.y = 0.0f;
        self.view.frame = f;
    }];
}
Floern
  • 31,495
  • 23
  • 98
  • 115
Mohammed Fathy
  • 332
  • 2
  • 10
0

i just created a lightweight keyboard handler to follow keyboard frame.

Usage:

 self.keyboardHandler = [EDKeyboardHandler new];

  [self.keyboardHandler listenWithBlock:^(KeyboardInfo *model)
  {
    //adjust view positions according to keyboard position here
  }];

and the KeyboardInfo model has the following properties:

typedef enum : NSUInteger {
    KeyboardStatusDidShow,
    KeyboardStatusWillShow,
    KeyboardStatusDidHide,
    KeyboardStatusWillHide,
} KeyboardStatus;

@interface KeyboardInfo:NSObject

@property (nonatomic,readonly) NSTimeInterval animationDuration;
@property (nonatomic,readonly) CGRect keyboardFrame;
@property (nonatomic,readonly) NSInteger animationCurve;
@property (nonatomic,readonly) KeyboardStatus status;

@end

check GitHub project for details and cocoaPods integration.

med
  • 1,450
  • 1
  • 14
  • 26