Logic for moving a text field above the keyboard

Right now I have the basic code to move the text box above the keyboard when starting editing. However, the size of the text field depends on the device and orientation. So, I wrote a rough way to do this, which does not always remain right above the keyboard, but instead grows when you rotate it, and therefore it does not look as professional as we would like.

The main point of my question is that there is logic to get the keyboard size based on the device and the orientation and use of this value automatically and, I hope, faster than that.

If this is the best way, please let me know. Otherwise, please indicate input. Here is the code I have. (This is just a move code, not a down code to prevent too much space).

- (void)textFieldDidBeginEditing:(UITextField *)textField { 

    //Get Device Type
    NSString *deviceType = [[UIDevice currentDevice] model];

    //Animate Text Field
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDuration:0.4];
    [UIView setAnimationBeginsFromCurrentState:YES];

    if ([deviceType isEqualToString:@"iPhone"]) {

        //Size For iPhone
        googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 210.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);

    } else if ([deviceType isEqualToString:@"iPad"]) {

        //Size for iPad
        googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 320.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);

    } else if ([deviceType isEqualToString:@"iPod touch"]) {

        //Size For iPod Touch
        googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 210.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);

    } 

    [UIView commitAnimations];

} 
+5
source share
3 answers

What you really want to do is watch for UIKeyboard (Did | Will) notifications (Show | Hide). They contain the start and end frames in the userInfo dictionaries, as well as the correct animation curve and duration.

So, after observing this notification when it was sent, move the text box based on the size of the frame transmitted in the notification, in accordance with the provided animation hints.

"" UIWindow: https://developer.apple.com/library/ios/#documentation/uikit/reference/UIWindow_Class/UIWindowClassReference/UIWindowClassReference.html

. , , .

@interface ViewController ()

- (void)viewControllerInit;

@end

@implementation ViewController

@synthesize textField;

- (id)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        [self viewControllerInit];
    }
    return self;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
    {
        [self viewControllerInit];
    }
    return self;
}


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


- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


#pragma mark - Notification Handlers

- (void)keyboardWillShow:(NSNotification *)notification
{
    // I'll try to make my text field 20 pixels above the top of the keyboard
    // To do this first we need to find out where the keyboard will be.

    NSValue *keyboardEndFrameValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardEndFrame = [keyboardEndFrameValue CGRectValue];

    // When we move the textField up, we want to match the animation duration and curve that
    // the keyboard displays. So we get those values out now

    NSNumber *animationDurationNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration = [animationDurationNumber doubleValue];

    NSNumber *animationCurveNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
    UIViewAnimationCurve animationCurve = [animationCurveNumber intValue];

    // UIView block-based animation methods anticipate not a UIVieAnimationCurve but a UIViewAnimationOptions.
    // We shift it according to the docs to get this curve.

    UIViewAnimationOptions animationOptions = animationCurve << 16;


    // Now we set up our animation block.
    [UIView animateWithDuration:animationDuration 
                          delay:0.0 
                        options:animationOptions 
                     animations:^{
                         // Now we just animate the text field up an amount according to the keyboard height,
                         // as we mentioned above.
                        CGRect textFieldFrame = self.textField.frame;
                        textFieldFrame.origin.y = keyboardEndFrame.origin.y - textFieldFrame.size.height - 40; //I don't think the keyboard takes into account the status bar
                        self.textField.frame = textFieldFrame;
                     } 
                     completion:^(BOOL finished) {}];

}


- (void)keyboardWillHide:(NSNotification *)notification
{

    NSNumber *animationDurationNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration = [animationDurationNumber doubleValue];

    NSNumber *animationCurveNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
    UIViewAnimationCurve animationCurve = [animationCurveNumber intValue];
    UIViewAnimationOptions animationOptions = animationCurve << 16;

    [UIView animateWithDuration:animationDuration 
                          delay:0.0 
                        options:animationOptions 
                     animations:^{
                         self.textField.frame = CGRectMake(20, 409, 280, 31); //just some hard coded value
                     } 
                     completion:^(BOOL finished) {}];

}
#pragma mark - View lifecycle

- (void)viewDidUnload
{
    [self setTextField:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

#pragma mark - UITextFieldDelegate

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

@end
+18

, , , .

.

, , .

.

@interface MainViewController : UIViewController

  @property (strong, nonatomic) IBOutlet UIScrollView *scroll;

@end    

@interface MainViewController ()
{
   CGPoint scrollOffset;
}
@end 

@implementation MainViewController

@synthesize scroll

-(void)viewWillAppear:(BOOL)animated
 {
    [[ NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillAppear:) name:UIKeyboardDidShowNotification object:nil];

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

 }


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

-(void)keyboardWillAppear:(NSNotification*) note
 {
   const CGFloat default_gap = 25.0f;

   NSValue *keyBoardEndFrameValue = [[ note userInfo ] objectForKey:UIKeyboardFrameEndUserInfoKey ];

   CGRect keyBoardFrame = [ keyBoardEndFrameValue CGRectValue ];


   offset = scroll.contentOffset;

   UIWindow *window = [[ UIApplication sharedApplication ] keyWindow];
   UITextField *textField = (UITextField*)[ window performSelector:@selector(firstResponder) ];

   //Gap between keyboard origin and the scroll origin, relative to parent.
   CGFloat distanceRelativeToParent = keyBoardFrame.origin.y - scroll.frame.origin.y; 


   //Distance between superview to textfield inside scroll. to determine if it necesary to scroll.
   CGFloat bound = (textField.frame.origin.y + textField.frame.size.height)+scroll.frame.origin.y; 

   CGFloat gapScroll = textField.frame.size.height+default_gap;

  if( bound >= keyBoardFrame.origin.y )
   {
     [ UIView animateWithDuration:.3 delay:0.0 options:UIViewAnimationCurveEaseOut 
   animations:^{

        [ scroll setContentOffset:CGPointMake(0, textField.frame.origin.y - distanceRelativeToParent +  gapScroll  ) animated:YES ];

   }
  completion:^(BOOL finished){

   }];
}

}

-(void) keyboardWillDisAppear:(NSNotification*) note
{   
   [ scroll setContentOffset:offset animated:YES ];
}
@end
+2

UIViewControllers have a property called interfaceOrientation and a UIInterfaceOrientationIsPortrait / Landscape function, so you can:

if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation){
//portrait logic
}
else{
//landcapeLogic
}

inside for every iPhone and iPad in your controller. From there, you can make your own way of measuring pixels, as you did before, because as far as I know, this is the easiest way to do this.

PS There is a function for checking and checking the landscape, but if the first if statement is false, it means that the device is not in the portrait, then it should be in the landscape, therefore, in a simple other.

0
source

All Articles