iOS Implements Automatic Upward Moving of Input Box Following Keyboard

Posted by cwarn23 on Tue, 09 Jul 2019 21:21:53 +0200

Scene Restoration

Sometimes in pages containing input boxes, clicking on input boxes will block part of the input boxes because the keyboard pops up, affecting the user experience. iOS does not deal with this problem by default, but we can achieve the effect of automatically uploading the keyboard pop-up input box by ourselves.


Test Page

Ideas for Realization

Watch the keyboard bouncing and retracting. When the bouncing keyboard will block the input box, the input box will move up with the keyboard at the appropriate distance. When the keyboard is retracted, the input box will return to its original state.

Specific scheme

1. Register two observers to watch the keyboard bounce and retract

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

2. In the above keyboard WillShow and keyboard WillHide methods, the input box is moved up and restored respectively.

  • Move upward
    When the pop-up keyboard obscures the input box on the page, we should move the input box above the keyboard, and when the keyboard does not obscure the input box, there is no need to operate. Therefore, in the ios coordinate system, we can obtain the Y coordinates of the upper end of the keyboard pop-up and the Y coordinates of the lower end of the input box respectively. By making a difference, we can judge whether the keyboard hides the input box. We can use the transform attribute of view for translation transformation instead of directly manipulating the frame of view. The advantage of this method is that when we want to restore the state of view, we can reset transform directly to 0, without any concern for calculating the distance when moving down.
  • Restore (move down to the original state)
    As mentioned earlier, we can implement the transform ation attribute of view simply by manipulating it at the right time.
- (void)keyboardWillShow:(NSNotification *)notification
{
    //Get the view in focus
    NSArray *textFields = @[phoneNemberText, verifyCodeText];
    UIView *focusView = nil;
    for (UITextField *view in textFields) {
        if ([view isFirstResponder]) {
            focusView = view;
            break;
        }
    }
    if (focusView) {
        //Get the time when the keyboard pops up
        double duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        //Getting Y coordinates at the top of the keyboard
        CGFloat keyboardY = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
        //Get the Y coordinates of the lower end of the input box relative to window
        CGRect rect = [focusView convertRect:focusView.bounds toView:[[[UIApplication sharedApplication] delegate] window]];
        CGPoint tmp = rect.origin;
        CGFloat inputBoxY = tmp.y + focusView.frame.size.height;
        //Calculate the difference between the two
        CGFloat ty = keyboardY - inputBoxY;
        NSLog(@"position keyboard: %f, inputbox: %f, ty: %f", keyboardY, inputBoxY, ty);
        //If the difference is less than 0, do translation transformation.
        [UIView animateWithDuration:duration animations:^{
            if (ty < 0) {
                self.view.transform = CGAffineTransformMakeTranslation(0, ty);
            }
        }];
    }
}

- (void)keyboardWillHide:(NSNotification *)notification
{
    //Get the time when the keyboard pops up
    double duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    //reduction
    [UIView animateWithDuration:duration animations:^{
        self.view.transform = CGAffineTransformMakeTranslation(0, 0);
    }];
}

It looks like this has perfected the way the input box moves up automatically with the keyboard, so we can have a cup of tea and have a little rest. Yes, in iOS 8 and later systems, it does work, but if your application needs to adapt to iOS 7 and support the horizontal screen, then the above way on iOS 7 can not move correctly as we expected.
Reason: On ios7, the frame of keyboard is calculated according to the windows coordinate system in the vertical screen state, and the rotation factor is not considered. Therefore, the frame of keyboard obtained under the horizontal screen is wrong. Also affected by this is the problem of acquiring screen width [UIScreen mainScreen].bounds when horizontal screen is used. In this case, not only can we not get the frame of keyboard correctly, but also the coordinate calculation of input box relative to window is wrong.
So on ios7, the Y coordinates at the top of keyboard and the Y coordinates at the bottom of input box relative to window s need to be handled separately. The Y coordinates at the top of the keyboard can be obtained by subtracting the height of the keyboard from the height of the screen. We use the following method to get the Y coordinates at the top of the keyboard.

- (CGFloat)getKeyboardY:(NSDictionary *)userInfo
{
    CGFloat screenHeight;
    CGFloat keyboardY = 0;
    CGFloat keyboardHeight = 0;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (( [[[UIDevice currentDevice] systemVersion] floatValue]<8)  && UIInterfaceOrientationIsLandscape(orientation))
    {
        screenHeight = [[UIScreen mainScreen] bounds].size.width;
        keyboardHeight = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.width;
        keyboardY = screenHeight - keyboardHeight;
    }
    else if (( [[[UIDevice currentDevice] systemVersion] floatValue]<8)  && UIInterfaceOrientationIsPortrait(orientation)) {
        screenHeight = [[UIScreen mainScreen] bounds].size.height;
        keyboardHeight = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
        keyboardY = screenHeight - keyboardHeight;
    }
    else {
        keyboardY = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
    }
    return keyboardY;
}

How to calculate the coordinates of the lower end of the input box relative to the window? The first one we get is actually based on the Y value in the coordinate system of the vertical screen, and what we expect is to get the Y value in the coordinate system of the horizontal screen. According to the relationship between the two coordinate systems, the coordinate obtained from the first transformation can be converted again, and the Y coordinate value in the coordinate system of the horizontal screen can be calculated. We use the following method to get the Y coordinates at the bottom of the input box.

- (CGPoint)getViewOriginPointToWindow:(UIView *)view
{
    CGPoint origin;
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8) {
        CGPoint focusViewPoint = [view convertPoint:CGPointZero toView:nil];
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (orientation == UIInterfaceOrientationLandscapeLeft) {
            origin.y = focusViewPoint.x;
            origin.x = [[[UIApplication sharedApplication] delegate] window].bounds.size.height - focusViewPoint.y;
        }
        else if (orientation == UIInterfaceOrientationLandscapeRight) {
            origin.y = [[[UIApplication sharedApplication] delegate] window].bounds.size.width - focusViewPoint.x;
            origin.x = focusViewPoint.y;
        }
        else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
            origin.y = [[[UIApplication sharedApplication] delegate] window].bounds.size.height - focusViewPoint.y;
            origin.x = [[[UIApplication sharedApplication] delegate] window].bounds.size.width - focusViewPoint.x;
        }
        else {
            origin = focusViewPoint;
        }
    }
    else {
        CGRect rect = [view convertRect:view.bounds toView:[[[UIApplication sharedApplication] delegate] window]];
        origin = rect.origin;
    }
    return origin;
}

So we changed the code that got the two Y coordinates to the following way:

//Getting Y coordinates at the top of the keyboard
CGFloat keyboardY = [self getKeyboardY:notification.userInfo];
//Get the Y coordinates of the lower end of the input box relative to window
CGPoint tmp = [self getViewOriginPointToWindow:focusView];
CGFloat inputBoxY = tmp.y + focusView.frame.size.height;

This perfectly realizes the effect that input box moves up automatically with keyboard.


Test Page

Topics: iOS Attribute less REST