filou
filou

Reputation: 1619

Xcode/iOS5: Move UIView up, when keyboard appears

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

Upvotes: 50

Views: 64787

Answers (9)

LuAndre
LuAndre

Reputation: 1133

Sample project Based on Apple Reference Keyboard Documentation

H File: (Don't Forget the UITextFieldDelegate)

@property (weak, nonatomic) IBOutlet UIScrollView *scrollview;

@property (weak, nonatomic) IBOutlet UIView *myView;


    //items on view
@property (weak, nonatomic) IBOutlet UISwitch *partySwitch;
@property (weak, nonatomic) IBOutlet UILabel *partyLabel;
@property (weak, nonatomic) IBOutlet UITextField *partyNameTextfield;

M file:

    //MARK: View Loading
- (void)viewDidLoad
{
    [super viewDidLoad];
        // Do any additional setup after loading the view.
}//eom

-(void)viewDidAppear:(BOOL)animated
{
    [self registerForKeyboardNotifications];
}//eom

    //MARK: textfield delegates
-(bool)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return true;
}//eom

    //MARK: - Keyboard Observers
    // Call this method somewhere in your view controller setup code.
- (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)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info      = [aNotification userInfo];
    CGSize kbSize           = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect        = myView.superview.frame;
    bkgndRect.size.height += kbSize.height;

    [myView.superview setFrame:bkgndRect];
    [scrollview setContentOffset:CGPointMake(0.0, myView.frame.origin.y-kbSize.height) animated:YES];
}//eom

    // Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets          = UIEdgeInsetsZero;
    scrollview.contentInset             = contentInsets;
    scrollview.scrollIndicatorInsets    = contentInsets;
}//eom

Upvotes: 0

This is Tendulkar solution, but keeping in mind original frame size and removing keyboard. This solution works for all devices.

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

[textField resignFirstResponder];

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
self.view.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height);
[UIView commitAnimations];
return YES;
 }


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

}

Do not forget set UITextField delegate!

Upvotes: 0

Kishore Suthar
Kishore Suthar

Reputation: 2983

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

Add the following constants:

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

Add this to your view controller:

CGFloat animatedDistance;

And add these methods to your code:

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

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

[self.view setFrame:viewFrame];

[UIView commitAnimations];
}

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

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

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

[self.view setFrame:viewFrame];

[UIView commitAnimations];
}

Upvotes: 12

Tendulkar
Tendulkar

Reputation: 5540

do like this. after keyboard visible use this code

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

}

Upvotes: 31

sreekanthk
sreekanthk

Reputation: 362

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    CGFloat y = textField.frame.origin.y;
    if (y >= 350) //not 380
   {
        CGRect frame = self.view.frame;
        frame.origin.y = 320 - textField.frame.origin.y;
        [UIView animateWithDuration:0.3 animations:^{self.view.frame = frame;}];
    }
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
CGRect returnframe =self.view.frame;
returnframe.origin.y = 0;
[UIView animateWithDuration:0.3 animations:^{self.view.frame = frame;}];
}

just edit these two methods.
simple answer to all d codes. In the if statement change the value according to the iphone i.e., if iphone 4S change it to 265 and in didbeginediting change the 320 to 240 and if iphone 5 change it to 350 and in didbeginediting method keep it as 320, because it is the logic if u understand

Upvotes: 1

Michael
Michael

Reputation: 2288

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

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

So my code looks like this:

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

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

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

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

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

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

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

Upvotes: 13

djromero
djromero

Reputation: 19641

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

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

Then, change as needed when keyboard shows up:

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

Finally, restore it when keyboard is hidden:

self.view.center = self.originalCenter;

Add animation sugar as you wish

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

Observing UIKeyboardDidShowNotification notification.

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

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

Do the opposite with UIKeyboardDidHideNotification.

-OR-

Implement UITextFieldDelegate

Detect when editing begin/end to move views around.

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

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

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

Upvotes: 98

James Webster
James Webster

Reputation: 32066

Presumably you have some code calling [myTextField becomeFirstResponder];. You should move your view just after this call.

Upvotes: 1

Related Questions