Monday, June 12, 2017

Move UITextField up when keyboard is overlapped

Leave a Comment

There is a subView presented on top of ViewA. Please find the screen layout below. When keyboard is shown on selecting UITextField even if its not overlapping with UITextField the view is scrolled up.

ViewA   -> UIButton  subView   -> UIScrollView         -> UITextField         -> UITextField      ViewA  ----------- |           | |           | |  Button   | |           | |           |  -----------     subView  -------------- |              | |              | |  UITextField | |  UITextField | |              |  -------------- 

I have registered keyboard notification

    - (void) viewWillAppear:(BOOL)animated {          [[NSNotificationCenter defaultCenter] addObserver:self                                                  selector:@selector(keyboardDidShow:)                                                      name:UIKeyboardDidShowNotification                                                    object:nil];          [[NSNotificationCenter defaultCenter] addObserver:self                                                  selector:@selector(keyboardWillBeHidden:)                                                      name:UIKeyboardWillHideNotification                                                    object:nil];     }   - (void) keyboardDidShow:(NSNotification *)notification {              NSDictionary* info = [notification userInfo];             CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];              UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);             self.scrollViewIb.contentInset = contentInsets;             self.scrollViewIb.scrollIndicatorInsets = contentInsets;              CGRect aRect = self.viewSelf.frame;             aRect.size.height -= kbRect.size.height;             CGRect frame = [self.viewSelf convertRect:self.activeField.frame toView:self.viewSelf.superview];             if (!CGRectContainsPoint(aRect, frame.origin) ) {                 [self.scrollViewIb scrollRectToVisible:self.activeField.frame animated:YES];             }     }  - (void) keyboardWillBeHidden:(NSNotification *)notification {          self.scrollViewIb.scrollEnabled = true;          UIEdgeInsets contentInsets = UIEdgeInsetsZero;         self.scrollViewIb.scrollIndicatorInsets = contentInsets;         [self.scrollViewIb setContentOffset:CGPointZero animated:false];  } 

4 Answers

Answers 1

There's a minor mistake in the coordinate system conversion: convertRect:toView: converts from the coordinate system of the receiver to the coordinates of the passed view.

If self.activeField.frame is a rectangle in the coordinate system of self.scrollViewIb as the code implies, then the conversion should go like this...

    CGRect frame = [self.scrollViewIb convertRect:self.activeField.frame toView:self.view]; 

Notice that I also suggest changing self.viewSelf.superview to self.view. If this code is running in the view controller that contains all of these subviews, then self.view should be sufficient and correct.

Answers 2

I think the problem is that you are always scrolling up, no matter if the keyboard overlaps your textfield or not.

You would have to get the frame of the textfield, calculate the distance to the bottom of the screen and check if the keyboard height (plus possible toolbar on top of it) would overlap your textfield and only then scroll up.

Anyways, I personally gave up on implementing scroll up behavior again and again. I now switched to using IQKeyboardManager. Simply install it as a Pod in your project and call IQKeyboardManager.sharedManager().enable = true in application(didFinishLaunchingWithOptions) and you are all set.

You even get a toolbar with next/previous and done button for free.

Answers 3

Don't get worry when we are in the world with the lots of open libraries.

Use KeyboardLib Lib by adding it to code or by the pod.

Just build it. On every Keyboard open that will show option for the Next, previous arrow with the Done button. Zero line of code with automatic event handling.

May be this one will solve the issue and a solution for the app betterment.

Answers 4

               Add this in your Controller or the other way is to create a category on UITextField               static CGFloat  const  MINIMUM_SCROLL_FRACTION = 0.4;             static CGFloat  const  MAXIMUM_SCROLL_FRACTION = 0.8;             static CGFloat  const  PORTRAIT_KEYBOARD_HEIGHT = 185;             static CGFloat  const  PORTRAIT_KEYBOARD_HEIGHT1 = 230;             static CGFloat  const  LANDSCAPE_KEYBOARD_HEIGHT = 140;             static CGFloat  const  KEYBOARD_ANIMATION_DURATION = 0.3;`                  - (void)textFieldDidBeginEditing:(UITextField *)textField view:(UIView *)view{CGRect textFieldRect = [view.window convertRect:textField.bounds fromView:textField];CGRect viewRect = [view.window convertRect:view.bounds fromView: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([[ UIScreen mainScreen ] bounds ].size.height == 568)                 {                     if (orientation == UIInterfaceOrientationPortrait ||                         orientation == UIInterfaceOrientationPortraitUpsideDown)                     {                         animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);                     }                     else                     {                         animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);                     }                 }                 else{                     if (orientation == UIInterfaceOrientationPortrait ||                         orientation == UIInterfaceOrientationPortraitUpsideDown)                     {                         animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction + 23);                     }                     else                     {                         animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction + 23);                     }                 }                  CGRect viewFrame = view.frame;                 viewFrame.origin.y -= animatedDistance;                 [UIView beginAnimations:nil context:NULL];                 [UIView setAnimationBeginsFromCurrentState:YES];                 [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];                 [view setFrame:viewFrame];                 [UIView commitAnimations];     }                  - (void)textFieldDidEndEditing:(UITextField *)textField view:(UIView *)view          CGRect viewFrame = view.frame;         viewFrame.origin.y += animatedDistance;                 [UIView beginAnimations:nil context:NULL];                 [UIView setAnimationBeginsFromCur rentState:YES];                 [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];                 [view setFrame:viewFrame];                 [UIView commitAnimations];             } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment