Last Updated: February 25, 2016
·
1.535K
· pxpgraphics

UIScrollView vs. UIWindow: Eternal iOS keyboard issue.

In my first year of iOS development, I've seen quite a few ways of moving UITextFields into view while the keyboard is present. Developers rejoice when they finally come to the conclusion of making the superview a delegate of a UIScrollView, and then incrementing the [contentSize height].

At first glance, this seems like an awesome way to move those little textfields above the mask of the active keyboard window being displayed above. However, I've done a lot of R&D on Apple-created applications and have found a common theme: These apps don't simply scroll the view while the user is editing or the textfield:didBecomeFirstResponder, they actually animate/transform the entire app's key window to move above the keyboard fold.

Here's how I've done it:


// Set up your static constants below your @import/@include.
// These floats will handle the scroll amount, speed and keyboard heights.
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; 

// Set a float ivar to manage the animatedDistance of the keyWindow.
@interface 
  CGFloat animatedDistance; 
@end 

// Begin the keyWindow scroll animation with this UITextField Delegate.
- (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]; 
} 

// Reset the keyWindow scroll animation with this UITextField Delegate.
- (void)textFieldDidEndEditing:(UITextField *)textField
{ 
  [textField resignFirstResponder]; 

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

These methods detect the keyboard window in it's current state and only executes the animation if the state is valid. I use these snippets in most of my apps—for the most part, they work fairly well. Hope this helps!

3 Responses
Add your response

I never noticed that happens.
Its possible.
Good solution.

over 1 year ago ·

@xeieshan, thanks! After looking through the latest iOS documentation, this may not be the solution they will continue to use post iOS7. I will post another pro tip as soon as the documentation is released publicly. :)

over 1 year ago ·

@xeieshan, it seems as though this method is even smoother for iOS 7 :) The animation is executed smoothly under the UINavigationController and UINavigationBar.

over 1 year ago ·