iOS 8 UIView not moving up when keyboard appears

2019-03-13 14:05发布

问题:

I am developing a chat app which has UITableView and a UIView containing a UITextField and a UIButton in it. I am using the following code to move the UIView up when keyboard appears.

(void)keyboardWillShow:(NSNotification *)notification
{

    NSDictionary* info = [notification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    [UIView animateWithDuration:0.2f animations:^{

        CGRect frame = self.inputView.frame;
       UIInterfaceOrientation orientation = self.interfaceOrientation;
    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation ==        UIInterfaceOrientationLandscapeRight)
            frame.origin.y -= kbSize.width;
        else
            frame.origin.y -= kbSize.height;

        self.inputView.frame = frame;
       ;
    }];
}

This code is working fine until iOS 7, but in iOS 8 UIView is not displaying above the keyboard.

Can anyone please suggest what could be the possible issue, or is there anything that has changed in iOS 8?

回答1:

Your code seems to be correct but i will prefer using UIKeyboardDidChangeFrameNotification or UIKeyboardWillChangeFrameNotification because these will tell you the change in keyboard frame when predictive text bar gets up or down when keyboard is in view.

In your ViewDidLoad add this

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardFrameDidChange:)
                                             name:UIKeyboardDidChangeFrameNotification object:nil];

and then paste this method in your ViewController

-(void)keyboardFrameDidChange:(NSNotification*)notification{
    NSDictionary* info = [notification userInfo];

    CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    [yourView setFrame:CGRectMake(0, kKeyBoardFrame.origin.y-yourView.frame.size.height, 320, yourView.frame.size.height)];
}

This will handle all your keyboard cases like when its up or down or change in its frame with predictive text bar

and also remove observer when you are leaving your view



回答2:

The accepted Answer is almost right. To match your view's animation to that of the keyboard you want to use the UIKeyboardWillChangeFrameNotification rather than the UIKeyboardDidChangeFrameNotification. That way the animations you kick off will precisely match that of the keyboard. Here's some code to do the entire thing. I use the animation of the keyboard to drive the animation of my autolayout constraint constants, but you can easily adapt this to animate an entire view frame. (Note, we have to use the old school style animations to hook into the UIKeyboardCurveInfoKey which provides an animation curve exactly matching the keyboard animation.

In viewDidLoad:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardFrameDidChange:)
                                             name:UIKeyboardWillChangeFrameNotification
                                           object:nil];

In ViewController:

- (void)keyboardFrameDidChange:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat height = kKeyBoardFrame.size.height; 
    [self.view removeConstraints:self.verticalButtonConstraints];
    NSDictionary *metrics = @{@"height" : @(height)};
    NSDictionary *views = @{@"nextButton" : self.nextButton};

    self.verticalButtonConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:  [nextButton(52)]-(height)-|" options:0 metrics:metrics views:views];
    [self.view addConstraints:self.verticalButtonConstraints];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.view layoutIfNeeded];
   [UIView commitAnimations];

}



回答3:

I just ran into this and made a discovery I thought I would share. In iOS 8 layout passes for the sub views of the main view will be done whenever the keyboard is about to appear or about to go away. These passes do not get done on iOS 7. So if you try to animate a sub view of the main view in keyBoardWillShow or keyboardWillChangeFrame the animation will get undone by the layout pass and your sub views that you tried to animate will move back to their original position. That is why keyboardDidChangeFrame works to animate the subviews and keyboardWillChangeFrame does not.

Something odd I noted as well is the timing of when these calls are made. It seems the first time that the keyboard appears after the app is launched, the call to keyboardDidChangeFrame happens too late to be able to animate with the keyboard so they slide up together, but on second and subsequent times the keyboard shows, the call to keyboardDidChangeFrame happens sooner and it seems you can actually animate the views along with the keyboard.

I must note that I am using C# and Xamarin as my development platform for iOS, so this may be different when using Swift or Obj-C.



回答4:

You can use an accessoryView, which will attach itself to the top of the keyboard. Alternatively, if you want more power over customization, you can use notifications as explained by @pankaj_wadwha to fetch the frame information. Bonus: you can also get the animation information (such as speed) so your view moves alongside the keyboard perfectly.